fix(task): add request timeout to devFetch so a stalled dev server rejects instead of hanging#4345
fix(task): add request timeout to devFetch so a stalled dev server rejects instead of hanging#4345spokodev wants to merge 1 commit into
Conversation
…cket rejects instead of hanging
|
@spokodev is attempting to deploy a commit to the Nitro Team on Vercel. A member of the Team first needs to authorize it. |
📝 WalkthroughWalkthroughThis PR adds request timeout support to the internal ChangesRequest timeout support for devFetch
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
test/unit/task.test.ts (1)
17-39: 💤 Low valueConsider reversing cleanup order for robustness.
The test correctly validates the timeout behavior. However, the cleanup order could be improved: currently
rmruns beforeserver.close(), but it's safer to close the server before removing the directory containing the socket file. Whileforce: truehandles busy files on most platforms, explicitly closing the server first is clearer and more robust.♻️ Suggested cleanup order
const cwd = await mkdtemp(join(tmpdir(), "nitro-task-test-")); - cleanups.push(() => rm(cwd, { recursive: true, force: true })); // A worker socket that accepts connections but never responds, like a // stalled dev server whose pid is still alive. const socketPath = join(cwd, "worker.sock"); const server = http.createServer(() => {}); cleanups.push(() => new Promise((resolve) => server.close(() => resolve()))); + cleanups.push(() => rm(cwd, { recursive: true, force: true })); await new Promise<void>((resolve) => server.listen(socketPath, resolve));🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@test/unit/task.test.ts` around lines 17 - 39, The cleanup order should close the test HTTP server before removing the temporary directory to avoid deleting the socket file while it's still in use; modify the cleanup registrations around the created server and rm so that the server.close cleanup (using server.close()) is pushed/registered before the rm cleanup (the rm(cwd, { recursive: true, force: true }) call), or combine them into a single cleanup that first awaits server.close() then calls rm, ensuring the server is closed prior to directory removal; update references in the test to use the cleanups array, server, server.close, and rm accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@test/unit/task.test.ts`:
- Around line 17-39: The cleanup order should close the test HTTP server before
removing the temporary directory to avoid deleting the socket file while it's
still in use; modify the cleanup registrations around the created server and rm
so that the server.close cleanup (using server.close()) is pushed/registered
before the rm cleanup (the rm(cwd, { recursive: true, force: true }) call), or
combine them into a single cleanup that first awaits server.close() then calls
rm, ensuring the server is closed prior to directory removal; update references
in the test to use the cleanups array, server, server.close, and rm accordingly.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: ab738c7d-2216-45f6-a2db-c277adb851ae
📒 Files selected for processing (3)
src/task.tssrc/types/runtime/task.tstest/unit/task.test.ts
Fixes #4292
Problem
devFetchinsrc/task.ts(used byrunTask()andlistTasks()) wrapshttp.request()without a timeout. The_pidIsRunningguard only checks that the dev server process is alive viakill(pid, 0)— it does not verify the socket is accepting or answering requests. When the worker is alive but stalled (or restarting and not yet listening on the unix socket), the returned promise never settles, sonitro task runin a CI pipeline hangs until a job-level kill with no diagnostic.Fix
Set the
timeoutoption onhttp.request()(default 30s) and destroy the request with a descriptive error on thetimeoutevent so the existingerror→rejectpath surfaces it to the caller.TaskRunnerOptionsgains an optionaltimeoutso callers (e.g. CI scripts) can set a tighter limit.Test
test/unit/task.test.tsspins an HTTP server on a unix socket that accepts connections but never responds, pointsnitro.dev.jsonat it with a live pid, and assertslistTasks({ cwd, timeout: 200 })rejects with the timeout error. Onmainthe promise never settles and the test fails by timing out; with the fix it rejects in ~200ms.pnpm vitest run test/unit/— the new test passes; the 4 pre-existing cloudflare preset failures reproduce identically on a clean checkout ofmainand are unrelated.pnpm fmtandpnpm typecheckclean.