問題
TypeScriptエコシステムの耐障害性ライブラリの多くはHTTPクライアント(axios-retry、p-retry、Polly.js)に依存するか、関数を.execute()という儀式を伴うクラスでラップする必要があります。データベースクエリ、内部サービス呼び出し、ファイル操作など任意の非同期関数に、再試行ロジック、タイムアウト、サーキットブレーカーを、重い依存関係を導入せずにラップしたい場合はどうでしょうか?
そこで登場するのがhouhouです。
houhouとは?
Houhouは、任意の非同期関数を合成可能な耐障害性ポリシーでラップする、依存関係ゼロのTypeScriptライブラリ(約500 LOC)です。ラップされた関数は完全に同じシグネチャを保持するため、元の関数と同じように呼び出せます。
import { task } from 'houhou'
const charge = task(chargeCard)
.retry(3)
.timeout(10_000)
.fallback(() => ({ status: 'pending' }))
await charge(account, amount)
全画面表示にする 全画面表示を終了
ポリシーの概要
Retry
固定または指数バックオフで失敗時に再実行します:
task(fetchUser).retry(3) // 短縮形
task(fetchUser).retry({
attempts: 5,
backoff: 'exponential',
jitter: true,
delay: 500
})
全画面表示にする 全画面表示を終了
Timeout
指定時間内に完了しなかった場合に拒否します:
task(fetchUser).timeout(5000)
全画面表示にする 全画面表示を終了
Fallback
失敗時に代替関数を実行します:
task(fetchUser).fallback(() => loadFromCache(id))
全画面表示にする 全画面表示を終了
Circuit Breaker
不健全なサービスへの繰り返しの呼び出しを防ぎます:
task(queryDb).circuitBreaker({
failureThreshold: 5,
successThreshold: 2,
resetTimeout: 30_000
})
全画面表示にする 全画面表示を終了
Delay
実行前に待機します:
task(syncData).delay(1000)
全画面表示にする 全画面表示を終了
ポリシーの順序が重要
ポリシーはネストされます。最後に呼び出されたメソッドが前のメソッドをラップします。実行順序は宣言順序の逆になります。
task(fn).retry(3).timeout(1000)
// → timeout が retry をラップ
// → 関数が実行 → 失敗時に再試行(最大3回) → 合計1秒のタイムアウト
// → タイムアウトが発生した場合、それ以上の再試行は行われない
全画面表示にする 全画面表示を終了
task(fn).timeout(1000).retry(3)
// → retry が timeout をラップ
// → 関数が実行 → 1秒のタイムアウト → タイムアウトが発生した場合、retry がキャッチ
// → サイクル全体が最大3回繰り返される
全画面表示にする 全画面表示を終了
型安全性 — ポリシーロック
各メソッドはロック可能です。TypeScriptはコンパイル時に同じポリシーを2回設定することを防ぎ、ランタイムのSetガードが実行時にもそれを強制します:
const t = task(fn).retry(3)
// @ts-expect-error — 'retry' はすでにロックされています
t.retry(2) // 実行時にも例外が発生
全画面表示にする 全画面表示を終了
AbortSignalによるキャンセル
HouhouはAbortControllerを使用して、タイムアウトが発生したときや外部シグナルが提供されたときに操作をキャンセルします。AbortSignalは関数の最後の引数として渡されます:
const fn = (url: string, signal?: AbortSignal) => fetch(url, { signal })
task(fn).timeout(5000)('https://api.example.com')
// → タイムアウトが発生 → controller.abort() → fetchがキャンセルされる
全画面表示にする 全画面表示を終了
独自の外部シグナルを渡すこともできます:
const controller = new AbortController()
const promise = task(fn).timeout(5000).retry(3)('url', controller.signal)
controller.abort() // すべてをキャンセル
全画面表示にする 全画面表示を終了
合成の例
ポリシーは任意の順序で流れるように連結できます:
const resilient = task(callApi)
.retry({ attempts: 3, backoff: 'exponential' })
.timeout(5000)
.fallback(loadFromCache)
.circuitBreaker({ failureThreshold: 5, successThreshold: 2, resetTimeout: 30_000 })
.delay(100)
全画面表示にする 全画面表示を終了
名前について
「houhou」は日本語で「方法」や「やり方」を意味します。これは、関数の実行方法に関するライブラリにふさわしい名前です。
試してみる
npm install houhou
# または
pnpm add houhou
yarn add houhou
全画面表示にする 全画面表示を終了
GitHub: https://github.com/smokeeaasd/houhou
npm: https://npmjs.com/package/houhou
0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.