@unikvs/retry
一時的な失敗を指数バックオフで再試行するストレージラッパーです。
概要
Retry は委譲先ストレージの一時的な失敗を指数バックオフで再試行し、読み書きが成功しやすくします。
不安定な回線や一時的な過負荷で失敗する操作の再試行に使います。再試行の可否判定と待機時間は調整できます。
nameはRetryです。isOpenは委譲先のinner.isOpenを返します。write・read・exists・delete・copy・move・clear・getWritable・getReadableを再試行し、open・close・onOtherWriteErrorは委譲のみ行います。- データとチャンクの変換は行わず、委譲先の型をそのまま保ちます。
インストールは次のコマンドで行います。
npm install @unikvs/retrypnpm add @unikvs/retryyarn add @unikvs/retrybun add @unikvs/retrynub add @unikvs/retryaube add @unikvs/retry使い方
Retry は IStorage を実装しています。UniKvs には persist() で渡します。
import { Retry } from "@unikvs/retry";
コンストラクターの引数は次のとおりです。
innerIStorage
委譲先のストレージです。
IStoragemaxRetries?number
初回試行の後の再試行回数です。0 では再試行しません。
number3initialDelayMs?number
初回の待機時間 (ミリ秒) です。
number100maxDelayMs?number
待機時間の上限 (ミリ秒) です。
number5000factor?number
待機時間の増加係数です。
number2jitter?boolean
待機時間にジッターを加えるかどうかです。
booleantrueretryable?RetryablePredicate
エラーがリトライ可能かどうかを判定する述語です。既定では isRetryableError を使用します。
RetryablePredicateonRetry?(info: RetryAttemptInfo) => void
再試行の直前に呼び出される通知です。
(info: RetryAttemptInfo) => void以下は、委譲先の一時的な失敗を再試行する例です。
import { Memory } from "@unikvs/memory";
import { Retry } from "@unikvs/retry";
import * as unikvs from "unikvs";
const kvs = new unikvs.Builder<{ k1: unikvs.PlainValue<string> }>()
.persist(new Retry(new Memory(), { maxRetries: 3 }))
.build();
await kvs.open();
await kvs.set("k1", "hello");
console.log(await kvs.get("k1")); // "hello"
await kvs.close();
Retry
一時的な失敗を指数バックオフで再試行するストレージラッパーです。待機時間は initialDelayMs * factor^(attempt-1) で増加し、maxDelayMs が上限になります。
RetryOptions
Retry のコンストラクターが受け取るオプションです。再試行回数と待機時間、判定述語を指定します。
RetryOperation
リトライ対象の操作名です。"write"・"read"・"exists"・"delete"・"copy"・"move"・"clear"・"getWritable"・"getReadable" のいずれかです。
RetryablePredicate
エラーがリトライ可能かどうかを判定する述語です。
RetryAttemptInfo
リトライが発生したときに通知される試行情報です。
operationRetryOperation
失敗した操作名です。
RetryOperationattemptnumber
失敗した試行回数 (1 始まり) です。
numbererrorunknown
発生したエラーです。
unknownnextDelayMsnumber
次の試行までの待機時間 (ミリ秒) です。
numberisRetryableError
既定のリトライ可否判定です。この判定では、存在しないキーなどの恒久的な失敗と、中断による失敗はリトライしません。
データ型
| 操作 | 対応するデータ型 |
|---|---|
write・read・copy・move |
委譲先のデータ型をそのまま保つ |
getWritable・getReadable のチャンク |
委譲先のチャンク型をそのまま保つ |
- すべての操作は委譲先の型をそのまま保ち、データとチャンクの変換を行いません。
- 再試行対象は読み書きと存在確認、削除、コピー、移動、全削除、ストリーム取得です。
- 内側ストレージが
copyまたはmoveを持たない場合は、read・write・deleteを組み合わせて同じ動作を再現します。 - フォールバックは読み出し後と移動先への書き込み後に中断シグナルを確認します。書き込み後に中断された
moveは移動元を削除しないため、移動元と移動先の両方が残ります。 openとcloseの失敗は再試行せず、そのまま伝播します。- 待機時間は指数関数的に増加して上限で抑えられ、
jitterがtrueの場合は上限の半分から上限までの範囲で変動します。
エラー
このパッケージが投げるエラーは次のとおりです。
RetryExhaustedError
意味
最大試行回数を超えても操作が成功しなかったときに投げます。最後に発生したエラーは cause に保持されます。
対処方法
cause から元の失敗原因を確認し、一時的な障害かどうかを切り分けてください。頻発する場合は maxRetries や待機時間、retryable の判定を見直してください。
例
以下は、RetryExhaustedError を捕捉する例です。
import { RetryExhaustedError } from "@unikvs/retry";
try {
await kvs.set("k1", "hello");
} catch (ex) {
if (ex instanceof RetryExhaustedError) {
console.log(ex.meta); // { operation: "write", attempts: 4 }
console.log(ex.cause); // 最後のエラー
} else {
throw ex;
}
}
RetryInvalidOptionError
意味
コンストラクターに不正なオプションが渡されたときに投げます。負の再試行回数や非整数、負の待機時間、1 未満の係数で投げます。
対処方法
meta.name のオプションを確認し、maxRetries は 0 以上の整数、initialDelayMs と maxDelayMs は 0 以上の有限数、factor は 1 以上の有限数を指定してください。
例
以下は、RetryInvalidOptionError を捕捉する例です。
import { RetryInvalidOptionError } from "@unikvs/retry";
try {
const retry = new Retry(inner, { maxRetries: -1 });
} catch (ex) {
if (ex instanceof RetryInvalidOptionError) {
console.log(ex.meta); // { name: "maxRetries", actual: -1 }
} else {
throw ex;
}
}
RetryUnsupportedOperationError
意味
委譲先のストレージが getWritable や getReadable を実装していないときに投げます。
対処方法
委譲先がストリーム操作に対応しているか確認し、未対応の場合はプレーンな読み書きを使ってください。
例
以下は、RetryUnsupportedOperationError を捕捉する例です。
import { RetryUnsupportedOperationError } from "@unikvs/retry";
try {
await kvs.stream("logs");
} catch (ex) {
if (ex instanceof RetryUnsupportedOperationError) {
console.log(ex.meta); // { operation: "getReadable", storage: "Bare" }
} else {
throw ex;
}
}
KeyNotFoundError と中断による AbortError は既定では再試行せず、そのまま伝播します。