これはなに?
Promise を返す関数(fetchとか)をリトライさせたいな、というときに使うコードです。
あちらこちらで何度も語られてきたものです。
今さら何書いてんのよ的な話ですみません。
お目汚し失礼します。
axiosもrxjsも使いたいけど使えない(バンドルサイズがぁー)みたいなとき用です。
本体コード
type Operation<T> = () => Promise<T>;
interface PromiseRetryConfig {
// エラー発生後のリトライ回数
count: number;
// エラー発生後の待ち時間(ms)
delay: number;
}
const wait = (delay: number) =>
new Promise((resolve) => setTimeout(resolve, delay));
/**
* エラー時リトライする
* @param operation
* @param config
* @returns
*/
export const promiseRetry = async <T>(
operation: Operation<T>,
config: PromiseRetryConfig
): Promise<T> => {
try {
return await operation();
} catch (err) {
if (config.count === 0) {
throw err;
}
await wait(config.delay);
return await promiseRetry(operation, {
count: config.count - 1,
delay: config.delay,
});
}
};
テストコード
import { promiseRetry } from "../src/libs/promise-retry";
describe("promiseRetry", () => {
const wait = (delay: number) =>
new Promise((resolve) => setTimeout(resolve, delay));
it("常に成功", async () => {
let executedCount = 0;
// Given
const operation = async () => {
await wait(1);
return ++executedCount;
};
const retryConfig = { count: 3, delay: 1 };
// When
const actual = await promiseRetry(operation, retryConfig);
// Then
expect(actual).toBe(1);
});
it("指定回数リトライするが失敗", async () => {
let executedCount = 0;
// Given
const operation = async () => {
await wait(1);
throw ++executedCount;
};
const retryConfig = { count: 3, delay: 1 };
try {
// When
await promiseRetry(operation, retryConfig);
// ここには来ない
expect.assertions(0);
} catch (err) {
// Then
expect(err).toBe(4); // 初回+3回リトライ
}
}, 6000);
it("リトライして成功する", async () => {
let executedCount = 0;
// Given
const operation = async () => {
await wait(1);
// 3回目で成功
if (++executedCount === 3) {
return executedCount;
} else {
throw executedCount;
}
};
const retryConfig = { count: 3, delay: 1 };
// When
const actual = await promiseRetry(operation, retryConfig);
// Then
expect(actual).toBe(3); // 初回+2回で成功
});
it("リトライさせないで失敗", async () => {
let executedCount = 0;
// Given
const operation = async () => {
await wait(1);
throw ++executedCount;
};
const retryConfig = { count: 0, delay: 1 };
try {
// When
await promiseRetry(operation, retryConfig);
// ここには来ない
expect.assertions(0);
} catch (err) {
// Then
expect(err).toBe(1); // 初回のみ
}
});
});