Fix bug which caused startup to hang if the clock was wound back since a previous session (#29558)
* SessionLock: reduce the stale time 30 seconds staring at a spinner while we wait for a stale lock to expire is rather painful. Pretty sure 15 seconds will be fine. * SessionLock: deal with the clock having been wound back If a previous session terminated uncleanly, and then the clock is wound back, we could be waiting a very long time for the previous session's claim to expire. We can fix this by simply treating a future claim the same as "now", and waiting for the normal stale timeout. * fixup! SessionLock: deal with the clock having been wound back
This commit is contained in:
committed by
GitHub
parent
a6e8d512d0
commit
f3653abe92
@@ -71,15 +71,15 @@ describe("SessionLock", () => {
|
||||
jest.advanceTimersByTime(5000);
|
||||
expect(checkSessionLockFree()).toBe(false);
|
||||
|
||||
// second instance tries to start. This should block for 25 more seconds
|
||||
// second instance tries to start. This should block for 10 more seconds
|
||||
const onNewInstance2 = jest.fn();
|
||||
let session2Result: boolean | undefined;
|
||||
getSessionLock(onNewInstance2).then((res) => {
|
||||
session2Result = res;
|
||||
});
|
||||
|
||||
// after another 24.5 seconds, we are still waiting
|
||||
jest.advanceTimersByTime(24500);
|
||||
// after another 9.5 seconds, we are still waiting
|
||||
jest.advanceTimersByTime(9500);
|
||||
expect(session2Result).toBe(undefined);
|
||||
expect(checkSessionLockFree()).toBe(false);
|
||||
|
||||
@@ -92,6 +92,40 @@ describe("SessionLock", () => {
|
||||
expect(onNewInstance2).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("A second instance starts up when the first terminated uncleanly and the clock was wound back", async () => {
|
||||
// first instance starts...
|
||||
expect(await getSessionLock(() => Promise.resolve())).toBe(true);
|
||||
expect(checkSessionLockFree()).toBe(false);
|
||||
|
||||
// oops, now it dies. We simulate this by forcibly clearing the timers.
|
||||
const time = Date.now();
|
||||
jest.clearAllTimers();
|
||||
expect(checkSessionLockFree()).toBe(false);
|
||||
|
||||
// Now, the clock gets wound back an hour.
|
||||
jest.setSystemTime(time - 3600 * 1000);
|
||||
expect(checkSessionLockFree()).toBe(false);
|
||||
|
||||
// second instance tries to start. This should block for 15 seconds
|
||||
const onNewInstance2 = jest.fn();
|
||||
let session2Result: boolean | undefined;
|
||||
getSessionLock(onNewInstance2).then((res) => {
|
||||
session2Result = res;
|
||||
});
|
||||
|
||||
// after another 14.5 seconds, we are still waiting
|
||||
jest.advanceTimersByTime(14500);
|
||||
expect(session2Result).toBe(undefined);
|
||||
expect(checkSessionLockFree()).toBe(false);
|
||||
|
||||
// another 500ms and we get the lock
|
||||
await jest.advanceTimersByTimeAsync(500);
|
||||
expect(session2Result).toBe(true);
|
||||
expect(checkSessionLockFree()).toBe(false); // still false, because the new session has claimed it
|
||||
|
||||
expect(onNewInstance2).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("A second instance waits for the first to shut down", async () => {
|
||||
// first instance starts. Once it gets the shutdown signal, it will wait two seconds and then release the lock.
|
||||
await getSessionLock(
|
||||
|
||||
Reference in New Issue
Block a user