fix(electron): share one deadline among waits before the PATH lookup starts

A bare-name launch that waited before the lookup was scheduled started
its own 10 s limit, so while startup was stuck every retry paid the full
delay again. The first early wait now sets the shared deadline; the
lookup still replaces it with its own budget when it starts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
4grayandClaude Opus 5.5 committed 2026-10-03 09:04:12 +02:00
1 parent b0a7554dc0
commit bb172fa6d8
2 files changed
+23 -5

No files matched your search

@@ -90,6 +90,23 @@ describe('login shell PATH', () => {
await expect(stuck.waitForLoginShellPath(60_000)).resolves.toBe(false);
});
it('lets waits before the lookup is scheduled share one deadline', async () => {
jest.useFakeTimers();
try {
const module = loadModule();
const first = module.waitForLoginShellPath();
await jest.advanceTimersByTimeAsync(6_000);
const retry = module.waitForLoginShellPath();
await jest.advanceTimersByTimeAsync(4_000);
// Both end at the first wait's deadline, not 10 s after the retry.
await expect(first).resolves.toBe(false);
await expect(retry).resolves.toBe(false);
await expect(module.waitForLoginShellPath()).resolves.toBe(false);
} finally {
jest.useRealTimers();
}
});
it('lets a launch retried within the budget wait for the PATH again', async () => {
let resolveShell: (path: string) => void = () => undefined;
const module = loadModule();
@@ -48,7 +48,8 @@ const settledOutcome = loginShellPathSettled.then(() => {
/**
* Resolves once the login shell PATH lookup has finished (successfully or
* not), or when its budget is spent; immediately on Windows. Before the
* lookup is scheduled, a wait lasts at most `limitMs`. Resolves to whether
* lookup is scheduled, waits end at a deadline shared from the first of
* them. `limitMs` caps a single wait. Resolves to whether
* the lookup had finished: false means the caller runs on the inherited
* PATH and should not keep a negative result.
*/
@@ -58,10 +59,10 @@ export function waitForLoginShellPath(
if (loginShellPathHasSettled) {
return Promise.resolve(true);
}
const remainingMs =
loginShellPathDeadline === null
? limitMs
: Math.min(limitMs, loginShellPathDeadline - Date.now());
// Waits before the lookup is scheduled share one deadline too, set by
// the first of them; scheduling the lookup replaces it with its budget.
loginShellPathDeadline ??= Date.now() + LOGIN_SHELL_PATH_WAIT_LIMIT_MS;
const remainingMs = Math.min(limitMs, loginShellPathDeadline - Date.now());
if (remainingMs <= 0) {
return Promise.resolve(false);
}