fix(mcp): clear timeout timer in bootstrapOneWorkspace#88
Conversation
When doBootstrap() resolves before the timeout, the setTimeout timer was never cleared, holding a ref on the event loop and preventing clean shutdown. Now clears the timer on success.
| const result = await Promise.race([doBootstrap(), timeout]); | ||
| clearTimeout(timer!); | ||
| return result; |
There was a problem hiding this comment.
🟡 Timer not cleared when Promise.race rejects, leaking the timeout on the error path
The new clearTimeout(timer!) on line 77 only executes on the success path. When doBootstrap() rejects (e.g., registerOrRotate throws a network error) before the timeout fires, Promise.race rejects and control jumps to the catch block at line 79, skipping the clearTimeout. The timer remains active for up to timeoutMs (default 5 seconds), keeping the Node.js event loop alive and potentially delaying process exit — especially noticeable in the stdio/CLI transport where bootstrapWorkspaces (packages/mcp/src/transports.ts:99-101) runs all workspaces concurrently and multiple leaked timers can accumulate.
| const result = await Promise.race([doBootstrap(), timeout]); | |
| clearTimeout(timer!); | |
| return result; | |
| const result = await Promise.race([doBootstrap(), timeout]); | |
| clearTimeout(timer!); | |
| return result; | |
| } catch (err) { | |
| clearTimeout(timer!); |
Was this helpful? React with 👍 or 👎 to provide feedback.
|
Preview deployed!
This preview shares the staging database and will be cleaned up when the PR is merged or closed. Run E2E testsnpm run e2e -- https://pr88-api.relaycast.dev --ciOpen observer dashboard |
When
doBootstrap()resolves before the timeout, thesetTimeouttimer was never cleared, holding a ref on the event loop for up totimeoutMs(default 5s) and preventing clean process shutdown.Fix: Store the timer reference and
clearTimeout()on success.Addresses Devin review comment on PR #86.
All 222 MCP tests passing.