実装

リトライが払わせる代償 — かける側ではなく、受ける側

著者: makemind · 2026年7月16日

レジがない間の末尾にこう書いた。

自動リトライがない。 ハーネスが明示的に繋ぎ直した。実際のアプリなら裏で周期的に試みるべきであり、その周期とバックオフはここで決めなかった。

この編がその周期を決める。そして決めるついでに、周期を間違えて決めると何が起きるかを測る。

受ける側から数える

リトライの記事の大半はかける側の話だ — どうやって自分のリクエストを通すか。

このサンプルのサーバーは反対側に立つ。試行が何回来たか、そしてそのうち何回が同じ200ミリ秒の中に集中したかを数える。

/// That second number is the one that matters. A gateway that is briefly down
/// does not care that you tried again. It cares how many of you tried again at
/// the same instant, because that is what keeps it down.

一時的に落ちたゲートウェイはあなたがもう一度かけたという事実に興味がない。興味があるのは何人が同じ瞬間にもう一度かけたかだ。それが落ちたままにさせるものだからだ。

急いでいるときに書かれるもの

/// Try again immediately. This is what gets written when the retry is added in
/// a hurry, and it is the strategy that turns a short outage into a long one.
class NoBackoff extends Backoff {
  @override
  int waitBefore(int n) => n == 1 ? 0 : 20;
}
RETRY IMMEDIATELY — 64 attempts. 18 attempts inside one 200ms window. try 1〜16、20ms間隔
RETRY IMMEDIATELY — 64 attempts. 18 attempts inside one 200ms window. try 1〜16、20ms間隔
RETRY IMMEDIATELY: 4 callers, 64 attempts total, 4 accepted, peak 18
  caller 1 attempt 1: straight away -> DOWN at 12ms
  caller 1 attempt 2: after 20ms -> DOWN at 58ms
  ...
  caller 1 attempt 16: after 20ms -> ACCEPTED at 708ms

通った。 700ミリ秒の障害を越え、四人とも決済された。

そしてゲートウェイはその間に64回叩かれた。

倍々に伸ばし、揺らす

@override
int waitBefore(int n) {
  if (n == 1) return 0;
  final base = 60 * (1 << (n - 2)); // 60, 120, 240, 480 ...
  // Full jitter: anywhere in [0, base]. Spreading matters more than being
  // punctual — nobody is waiting on an exact millisecond here.
  return _rng.nextInt(base + 1);
}
EXPONENTIAL + JITTER — 25 attempts. 13 attempts inside one 200ms window. try 1〜6
EXPONENTIAL + JITTER — 25 attempts. 13 attempts inside one 200ms window. try 1〜6
EXPONENTIAL + JITTER: 4 callers, 25 attempts total, 4 accepted, peak 13
  caller 1 attempt 1: straight away -> DOWN at 13ms
  caller 1 attempt 2: after 53ms  -> DOWN at 70ms
  caller 1 attempt 3: after 87ms  -> DOWN at 159ms
  caller 1 attempt 4: after 143ms -> DOWN at 305ms
  caller 1 attempt 5: after 389ms -> DOWN at 697ms
  caller 1 attempt 6: after 449ms -> ACCEPTED at 1150ms

同じ障害、同じ人数、同じ結果。 四人とも決済された。

試行は64回から25回。 2.6倍少ない。

このコンテンツは開発者以上が必要です

サインインしてプランをアップグレードすると続きを読めます。

プランを見る
Twitter