<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Idempotency on Yen Tsai dev</title>
    <link>https://yentsaidev.com/tags/idempotency/</link>
    <description>Recent content in Idempotency on Yen Tsai dev</description>
    <generator>Hugo -- 0.147.0</generator>
    <language>zh-tw</language>
    <lastBuildDate>Fri, 04 Sep 2026 20:16:00 +0800</lastBuildDate>
    <atom:link href="https://yentsaidev.com/tags/idempotency/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>從一次 SQL Timeout 排查，整理 Transaction、Retry 與 Idempotency</title>
      <link>https://yentsaidev.com/blog/sql-timeout-transaction-retry-idempotency/</link>
      <pubDate>Fri, 04 Sep 2026 20:16:00 +0800</pubDate>
      <guid>https://yentsaidev.com/blog/sql-timeout-transaction-retry-idempotency/</guid>
      <description>&lt;p&gt;最近在處理一個付款流程問題時，遇到一支 API 發生 SQL timeout。&lt;/p&gt;
&lt;p&gt;第一時間我先往 SQL query 本身去想，但後來把整個 request flow 跟時間線整理出來後，才發現問題跟前一支付款 API 的 transaction scope 有關。&lt;/p&gt;
&lt;p&gt;這次排查剛好把幾個平常分開看的概念串在一起：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Transaction&lt;/li&gt;
&lt;li&gt;Database Lock&lt;/li&gt;
&lt;li&gt;Third-party API&lt;/li&gt;
&lt;li&gt;Retry&lt;/li&gt;
&lt;li&gt;Compensation&lt;/li&gt;
&lt;li&gt;Idempotency&lt;/li&gt;
&lt;li&gt;Race Condition&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;這篇就記錄一下整個思考過程。&lt;/p&gt;
&lt;h2 id=&#34;問題現象&#34;&gt;問題現象&lt;/h2&gt;
&lt;p&gt;流程大概是這樣：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;付款 API
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ↓
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;呼叫第三方系統
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ↓
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;後續查詢 API
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ↓
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;成功頁面
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;實際發生問題時，付款 API 呼叫第三方系統後等待了很長一段時間。&lt;/p&gt;
&lt;p&gt;同時間，後續另一支 API 需要查詢資料，但最後發生 SQL timeout，導致後面的流程沒有繼續。&lt;/p&gt;
&lt;p&gt;一開始看到 SQL timeout，很自然會先懷疑：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Query 是不是太慢？&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;但把兩支 API 的時間線放在一起看後，我注意到前一支付款 API 有使用 transaction，而且兩個流程都會碰到同一筆資料。&lt;/p&gt;
&lt;h2 id=&#34;開始懷疑-blocking&#34;&gt;開始懷疑 Blocking&lt;/h2&gt;
&lt;p&gt;我的思路是：付款 API 有 transaction，後面的 API 又在讀相同資料，而且前面的 transaction 還沒有結束，那就有可能是 lock 還沒被釋放。&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
