1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

タイムアウト時の冪等性の考慮

1
Last updated at Posted at 2026-09-03

はじめに

タイムアウトした場合に起こる冪等性の性質についてまとめます。

背景

前回は冪等性のことについて触れました。

今回はタイムアウトしたために、ユーザー側(クライアント)は何回もリトライするけど、サーバー側は1回しっかりと登録されていることを確認します。

クライアントとサーバーで待ち時間を作り、処理をずらす

図にすると以下のような感じにします。

クライアント側                                      サーバー側
    │                                                  │
    │  処理開始                                         │
    │                                                  │
    │  API呼び出し ──────────────────────────────────→ │
    │                                                  │
    │                                                  │ 処理開始
    │                                                  │
    │  3秒待つ                                          │
    │                                                  │
    │  タイムアウト                                     │
    │                                                  │
    │  処理終了                                         │

クライアント側で処理開始しますが、3秒でタイムアウトします。
そのため、サーバー側の処理完了を待たず、処理終了してしまいます。

コード
route

import { supabase } from "../../../utils/supabase";

export async function POST() {
    console.log("開始");

    await new Promise((resolve) => {
        setTimeout(resolve, 5000);
    });

    console.log("5秒経過");

    const idempotencyKey = "test-timeout-001";
    const { data, error } = await supabase.from("favorites_dev").insert([{ workspace_set_dev_id: 2, user_id: "<USER_ID>", idempotency_key: idempotencyKey,},])
        .select();

    if (error) {
        console.error(error);

        return Response.json(
            { error: error.message },
            { status: 500 }
        );
    }

    console.log("完了");

    return Response.json(data);
}
page
"use client";

export default function TimeoutTest() {

    const testTimeout = async () => {

        const controller = new AbortController();

        const timeoutId = setTimeout(() => {
            console.log("3秒経過 → タイムアウト");
            controller.abort();
        }, 3000);

        try {
            console.log("API呼び出し開始");

            const response = await fetch("/api/test-timeout", {
                method: "POST",
                signal: controller.signal,
            });

            const data = await response.json();

            console.log("APIレスポンス:", data);

        } catch (error) {

            if (
                error instanceof DOMException &&
                error.name === "AbortError"
            ) {
                console.log("タイムアウトしました");
            } else {
                console.error("その他のエラー:", error);
            }

        } finally {
            clearTimeout(timeoutId);
        }
    };

    return (
        <button onClick={testTimeout}>
            タイムアウトテスト
        </button>
    );
}

image.png

何度もPOSTしましたが、DBに登録されているデータは1つだけでした。
{"idx":1,"id":14,"created_at":"2026-09-03 12:25:54.909377+00","workspace_set_dev_id":2,"user_id":"<USER_ID>","idempotency_key":"test-timeout-001"}

しっかりとエラーも出ています。

{
  code: '23505',
  details: 'Key (idempotency_key)=(test-timeout-001) already exists.',
  hint: null,
  message: 'duplicate key value violates unique constraint "favorites_dev_idempotency_key_key"'
}

おわりに

今回はタイムアウトがあった場合に冪等性担保されるかを確認しました。
しかし、クライアント側ではどうなっているかわからないため通知が必要となります。次回以降その対応をしていきます。

参考文献

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?