Skip to content

fix(tasks): stop scheduled tasks on runtime close - #4416

Merged
pi0 merged 5 commits into
nitrojs:mainfrom
Prains:fix/scheduled-task-runner-unref
Oct 3, 2026
Merged

pi0 merged 5 commits into
nitrojs:mainfrom
Prains:fix/scheduled-task-runner-unref

Conversation

@Prains

@Prains Prains commented Jul 10, 2026 •

Copy link
Copy Markdown
Contributor

Resolves #4415.

Problem

Scheduled Croner timers must stay referenced for custom CLI-only entries, but referenced timers also need to be released during graceful server shutdown.

Change

  • Keep scheduled task timers referenced while the runtime is active.
  • Retain Croner jobs and stop them from the Nitro close hook.
  • Forward srvx server shutdown to the Nitro runtime close hook for Bun, Node, Node cluster, and Deno server presets.
  • Cover timer ownership, close cleanup, and srvx lifecycle forwarding with unit tests.

Verification

  • pnpm test
  • Rollup: 900 passed, 137 skipped, 13 todo
  • Rolldown: 900 passed, 137 skipped, 13 todo
  • Bun 1.3.14 SIGTERM reproduction: process exits with code 0 after Server closed successfully.

@Prains
Prains requested a review from pi0 as a code owner July 10, 2026 08:58
@vercel

vercel Bot commented Jul 10, 2026

Copy link
Copy Markdown

@Prains is attempting to deploy a commit to the Nitro Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jul 10, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 5d1120f2-f76e-410a-a6e5-24a29e3eb0a9
📥 Commits

Reviewing files that changed from the base of the PR and between 7612a1a and 7879c6f.

📒 Files selected for processing (2)
  • docs/1.docs/50.tasks.md
  • test/unit/task.test.ts
 __________________
< I see dead code. >
 ------------------
  \
   \   (\__/)
       (•ㅅ•)
       /   づ

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: c7b8768f-9c6a-45eb-951d-f1927c5d76c6

📥 Commits

Reviewing files that changed from the base of the PR and between 206f243 and 7612a1a.

📒 Files selected for processing (2)
  • src/runtime/internal/task.ts
  • test/unit/task.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • test/unit/task.test.ts
  • src/runtime/internal/task.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

startScheduleRunner now retains scheduled Cron instances and stops them through Nitro’s "close" hook. Tests cover multiple jobs and continue-on-error behavior when one stop() call throws.

Changes

Runtime shutdown lifecycle

Layer / File(s) Summary
Scheduled task shutdown cleanup
src/runtime/internal/task.ts, test/unit/task.test.ts
startScheduleRunner stores created Cron instances and stops each one during the Nitro "close" hook. Stop errors are logged without preventing later jobs from stopping. Unit tests cover hook registration, multiple stop calls, and stop failures.

Priority: ➖ Normal — Impact reflects medium issue severity.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Severity of issue fixed: Medium

Merge Risk: ⚪ Minimal · up to 7612a

Scheduled Croner tasks now remain active during server operation and stop on Nitro close, allowing graceful shutdown without lingering timers. No current merge-blocking risk remains.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 3 functions across 3 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title follows Conventional Commits syntax and accurately describes stopping scheduled tasks when the runtime closes.
Description check ✅ Passed The description explains the scheduled-task shutdown problem, the Croner cleanup change, and the related verification.
Linked Issues check ✅ Passed The changes retain scheduled Croner jobs during runtime and stop them through the Nitro close hook, which addresses issue #4415 by allowing graceful shutdown to terminate the process normally.
Out of Scope Changes check ✅ Passed The code and test changes are limited to scheduled-task lifecycle cleanup and its regression coverage, which are within the scope of issue #4415.
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pi0 pi0 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While this is a valid fix for durable servers, if someone makes a custom entry like CLI only app, scheduled tasks should keep running even without server listener ref.

I think better alternative would be to make sure scheduled tasks are destroyed when calling nitro close hook in runtime.

@Prains Prains changed the title fix(tasks): unref scheduled task timers fix(tasks): stop scheduled tasks on runtime close Jul 11, 2026
@Prains

Prains commented Jul 11, 2026

Copy link
Copy Markdown
Contributor Author

@pi0 Updated in 089466b8: scheduled timers remain referenced for CLI-only entries, Croner jobs stop from the Nitro close hook, and srvx server shutdown now forwards to that runtime hook for Bun, Node, Node cluster, and Deno server presets. The Bun SIGTERM reproduction exits cleanly, and the full Rollup/Rolldown suite passes.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 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.

Inline comments:
In `@src/runtime/internal/app.ts`:
- Around line 42-50: Make shutdown resilient in nitroRuntimeHooksPlugin at
src/runtime/internal/app.ts lines 42-50 by catching failures from the memoized
close hook and ensuring the original server.close call always proceeds; in
src/runtime/internal/task.ts lines 69-73, wrap each job.stop() invocation in
try/catch so one failing job does not prevent subsequent jobs from stopping or
reject the close hook.

In `@src/runtime/internal/task.ts`:
- Around line 75-89: Update the Cron construction in the scheduledTasks loop to
pass an options object with unref enabled, while preserving the existing
scheduled callback. Update the related unit test expectation to include this
Cron option.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4cb6a897-b57a-4a6c-85f1-583e8efacb1c

📥 Commits

Reviewing files that changed from the base of the PR and between eee0abd and 089466b.

📒 Files selected for processing (8)
  • src/presets/bun/runtime/bun.ts
  • src/presets/deno/runtime/deno-server.ts
  • src/presets/node/runtime/node-cluster.ts
  • src/presets/node/runtime/node-server.ts
  • src/runtime/internal/app.ts
  • src/runtime/internal/task.ts
  • test/unit/runtime-app.test.ts
  • test/unit/task.test.ts

Comment thread src/runtime/internal/app.ts Outdated
Comment thread src/runtime/internal/task.ts
@Prains
Prains requested a review from pi0 July 13, 2026 10:56
@pi0x pi0x added bug Something isn't working v3 labels Sep 2, 2026
@xmlking

xmlking commented Sep 4, 2026

Copy link
Copy Markdown

I noticed same issue with bun runtime with scheduledTasks. looking to this fix

@pi0x

pi0x commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Rebased this on latest main locally to check it. Notes:

  • Main already landed the same server-close wiring in fix(node, bun, deno): call runtime close hooks on server shutdown #4574 (setupCloseHooks in src/runtime/internal/shutdown.ts). So nitroRuntimeHooksPlugin, the four preset edits and test/unit/runtime-app.test.ts are now duplicates. Please drop them.
  • The other half still applies and is the useful part: keeping the Cron jobs and stopping them on the close hook. It also fixes the dev server, which already calls that hook.
  • Nothing here uses unref or Node-only APIs, so workers and edge are fine.
  • Small nit: import useNitroHooks from ./app.ts, like shutdown.ts does.
  • node_middleware starts schedules but has no server to close, so crons still run on there.

I could not push my rebase from this environment.

This comment was written by an AI assistant on behalf of the Nitro maintainers. Please double-check anything that looks wrong.

@Prains
Prains force-pushed the fix/scheduled-task-runner-unref branch from 92d131a to 7612a1a Compare September 8, 2026 09:40
@coderabbitai

coderabbitai Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@Prains

Prains commented Sep 8, 2026 •

Copy link
Copy Markdown
Contributor Author

@pi0, updated the branch based on the latest feedback and rebased it onto main (206f243c). The current HEAD is 7612a1a0.

  • Removed nitroRuntimeHooksPlugin, the four server preset changes, and test/unit/runtime-app.test.ts. The branch now relies on the existing setupCloseHooks from fix(node, bun, deno): call runtime close hooks on server shutdown #4574.
  • Kept the Cron job references and cleanup through the runtime close hook, including per-job stop() error isolation and tests.
  • Changed the useNitroHooks import to ./app.ts and updated the test mock. No unref or Node-only APIs were added.
  • Left node_middleware behavior unchanged: closing the external server does not automatically call the Nitro close hook, so the integration still needs to connect the host lifecycle to that runtime hook explicitly.

Validation: formatting, lint, build, typecheck, and all 7 targeted tests passed. The full Rollup and Rolldown runs each had 1,039 passing tests and one failure in test/vite/hmr.test.ts involving an extra full-reload. All 7 HMR tests passed when rerun separately with each builder. The full pipeline is therefore not reported as fully passing; this PR does not change the HMR code.

For transparency, this comment was prepared with AI assistance. The feedback was checked against the current code, and the validation results above include the observed test failures.

spokodev added a commit to spokodev/nitro that referenced this pull request Sep 8, 2026
…nasked

A flat default capped runTask itself, since the socket stays idle for as long
as the task runs. listTasks keeps a 30s default because the dev server answers
it immediately; runTask now has none and takes one through TaskRunnerOptions.

Passing `timeout: undefined` was not equivalent to omitting it: the socket
still emitted a `timeout` event when the peer closed the idle connection, and
the handler rejected with "after undefinedms". Both the option and the handler
are now set only when a timeout is configured.

Renames the test file to task-runner.test.ts to leave test/unit/task.test.ts
to nitrojs#4416, which covers the runtime scheduler.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@pkg-pr-new

pkg-pr-new Bot commented Oct 3, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/nitro@4416

commit: 7612a1a

Rename leftover unref test, use vi.stubEnv for TEST, and document close-hook cleanup for node_middleware.
@pi0
pi0 merged commit a9e4ab0 into nitrojs:main Oct 3, 2026
9 of 11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working v3

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Scheduled tasks keep Bun process alive after graceful shutdown

4 participants