-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add limited retries to lock acquisition (#49)
The lock acquisition could continue forever. This ensures there is a hard limit on the number of times its attempted.
- Loading branch information
1 parent
c93893a
commit 77906b2
Showing
3 changed files
with
61 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { retry } from "../src/retry"; | ||
|
||
describe("retry", () => { | ||
it("returns function output on success", async () => { | ||
const result = await retry(() => Promise.resolve(true)); | ||
expect(result).toBe(true); | ||
}); | ||
|
||
it("throws error after exactly specified number of times", async () => { | ||
const maxRetries = 5; | ||
let timesCalled = 0; | ||
const result = await retry( | ||
async () => { | ||
timesCalled++; | ||
return Promise.resolve(timesCalled === maxRetries); | ||
}, | ||
maxRetries, | ||
"did not execute enough times", | ||
0 | ||
); | ||
|
||
expect(timesCalled).toBe(maxRetries); | ||
expect(result).toBe(true); | ||
}); | ||
|
||
it("pauses between executions", async () => { | ||
const waitTimeMs = 1234; | ||
const perform = async () => | ||
await retry(() => Promise.resolve(false), 2, "intentional final failure", waitTimeMs); | ||
|
||
const start = Date.now(); | ||
await expect(perform()).rejects.toThrow("intentional final failure"); | ||
const execTimeMs = Date.now() - start; | ||
|
||
// Must wait at least this long | ||
expect(execTimeMs).toBeGreaterThanOrEqual(waitTimeMs); | ||
// Will be some delay for the expectation, but more than a second out causes unpredictability | ||
expect(execTimeMs).toBeLessThan(waitTimeMs + 1000); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
export const retry = async ( | ||
fn: () => Promise<boolean>, | ||
retries = 3, | ||
finalError = `Retried ${retries} times without success`, | ||
waitBetweenMs = 1000 | ||
): Promise<boolean> => { | ||
for (let i = 0; i < retries; i++) { | ||
const success = await fn(); | ||
if (success) { | ||
return Promise.resolve(true); | ||
} | ||
|
||
if (i < retries - 1) { | ||
await new Promise(resolve => setTimeout(resolve, waitBetweenMs)); | ||
} | ||
} | ||
throw new Error(finalError); | ||
}; |