「コードテイマー」は、魔物使いのカイナが、暴れる非同期・並行処理のコードを直していく全12話の連載です。依頼人のコードで起きる困りごとを、まず観察して再現し、型とテストで守る形に直します。実装は TypeScript です。
どの話からでも読めます。物語仕立てですが、どの話も直す前と後のコード、それを確かめるテストが載っています。何が変わったかを追えれば十分です。
このページは目次を兼ねた案内板です。初めてなら「まず読むなら」の3本から、手元に困っているコードがあるなら「困りごとから探す」から選んでください。
まず読むなら
- Race Condition — ボタン連打で二重送信になる回。await をまたぐ処理は誰でも書くので、フロントでもバックエンドでも明日のコードにそのまま効く
- Semaphore — 並列数を上げたら逆に全体が落ちる回。同時に動く数を絞るだけで、速さと安定の両方が手に入る
- State Machine — boolean フラグを足し続けた末に、ありえない状態へ入り込む回。フラグが3本を超えたコードを抱えているなら、いちばん効く
困りごとから探す
たまに二重に動く、更新が消える
- Race Condition — 連打で同じ処理が二重に走る
- Optimistic Locking — 同時更新の片方が黙って上書きされる
- State Machine — フラグの組み合わせで、ありえない状態に入る
負荷が高いと、全体が落ちる
- Semaphore — 並列数を上げすぎて共倒れになる
- Token Bucket — 制限しているはずが、窓の境目で2倍通る
- Bulkhead — 重い処理が枠を使い切り、大事な処理が動けない
外部サービスが落ちたとき、巻き込まれる
- Exponential Backoff — リトライの連発が、かえって復旧を遅らせる
- Circuit Breaker — 落ちた相手を待ち続けて、無関係な機能まで止まる
- Eventual Consistency — 通知を取りこぼした側だけ、古い状態のまま戻らない
止まる、残る、終わらない
- Deadlock — 互いのロックを待ち合って、永久に止まる
- AbortController — 消したはずの処理が裏で動き続ける
- Graceful Shutdown — 終了時に、処理中の仕事と接続を取り残す
全話一覧
- ボタンを連打すると、同じ処理が二重に走って二重送信になる。await をまたぐ前に実行中フラグを立てて締め出す【Race Condition】
- 消したはずの検索が裏で動き続け、リソースを握ったまま離さない。キャンセルを最後まで伝える【AbortController】
- 障害のたびにリトライを連発し、かえって復旧を遅らせる。待ち時間を倍々に伸ばして散らす【Exponential Backoff】
- 並列数を上げたら、かえって全体が落ちた。同時に動く数を上限で絞って待たせる【Semaphore】
- 2つの処理が互いのロックを待ち合って、永久に止まる。ロックを取る順番を全体で1つに揃える【Deadlock】
- 上限は守っているのに、切り替わりの一瞬だけ2倍通ってしまう。窓で区切らず溜まる速さで制限する【Token Bucket】
- boolean フラグを足すたびに、ありえない状態が増えていく。状態を1つの型にまとめて書けなくする【State Machine】
- 同時に更新した片方が、気づかないうちに消えている。バージョンを持たせて衝突した方にやり直させる【Optimistic Locking】
- 通知を取りこぼした画面だけ、古い状態のまま戻らない。push と定期取得を併用して必ず追いつかせる【Eventual Consistency】
- 落ちた外部サービスを待ち続けて、無関係な機能まで巻き込んで止まる。失敗が続いたら呼ぶのをやめる【Circuit Breaker】
- 重い処理が接続を使い切り、大事な処理が動けなくなる。機能ごとに使える枠を分けておく【Bulkhead】
- 終了シグナルを受けて即座に落とすと、処理中のリクエストと接続を取り残す。新規を止めて、処理中を待ってから閉じる【Graceful Shutdown】
