Skip to content

Commit

Permalink
fix(utils): stop immediately when retry limited (#576)
Browse files Browse the repository at this point in the history
  • Loading branch information
homura authored Nov 29, 2023
1 parent ddb4d5e commit 85f80e9
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 19 deletions.
49 changes: 34 additions & 15 deletions packages/utils/src/async/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,22 @@ export function timeout<T>(
typeof options === "number" ? options : options.milliseconds ?? 1000;
const message = typeof options === "number" ? undefined : options.message;

const timeoutPromise = delay(milliseconds).then(() =>
Promise.reject(
message instanceof Error ? message : createTimeoutError(message)
)
);
return new Promise((resolve, reject) => {
const timeoutTask = setTimeout(() => {
reject(message instanceof Error ? message : createTimeoutError(message));
}, milliseconds);

return race<T>([promise, timeoutPromise]);
promise.then(
(value) => {
clearTimeout(timeoutTask);
resolve(value);
},
(error) => {
clearTimeout(timeoutTask);
reject(error);
}
);
});
}

export interface RetryOptions {
Expand All @@ -73,20 +82,30 @@ export function retry<T>(
delay: delayMs = 0,
} = options;

let lastErr: unknown;
let times = 0;
let currentRetryTimes = 0;

const retryPromise = new Promise<T>((resolve, reject) => {
function retryRun() {
times++;
if (times > retries) {
reject(lastErr);
function handleError(err: unknown) {
if (currentRetryTimes > retries) {
reject(err);
return;
}
Promise.resolve(run()).then(resolve, (e) => {
lastErr = e;

currentRetryTimes++;

if (delayMs) {
delay(delayMs).then(retryRun);
});
} else {
retryRun();
}
}

function retryRun() {
try {
Promise.resolve(run()).then(resolve, handleError);
} catch (err) {
handleError(err);
}
}

retryRun();
Expand Down
27 changes: 23 additions & 4 deletions packages/utils/tests/async.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,14 @@ test("async#timeout", async (t) => {

test("async#retry", async (t) => {
function passOn(times: number): () => Promise<void> {
let count = 0;
let runTimes = 0;
return () =>
new Promise<void>((resolve, reject) => {
count++;
if (count >= times) resolve();
else reject(new Error("Failed"));
if (runTimes > times) {
return resolve();
}
runTimes++;
reject(new Error("Failed"));
});
}

Expand Down Expand Up @@ -71,3 +73,20 @@ test("async#retry with timeout", async (t) => {
t.true(called);
t.true(failed);
});

test("async#retry with delay", async (t) => {
const before = Date.now();

await t.throwsAsync(() =>
retry(
() => {
throw new Error("delay");
},
{ retries: 5, delay: 50, timeout: 1000 }
)
);

const after = Date.now();

t.true(after - before >= 50 * 5);
});

2 comments on commit 85f80e9

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀 New canary release: 0.0.0-canary-85f80e9-20231129095024

npm install @ckb-lumos/[email protected]

@vercel
Copy link

@vercel vercel bot commented on 85f80e9 Nov 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.