Skip to content

feat(tasks): expose req and waitUntil in context#4037

Merged
pi0 merged 4 commits into
nitrojs:mainfrom
RihanArfan:feat/tasks-waituntil
Feb 18, 2026
Merged

feat(tasks): expose req and waitUntil in context#4037
pi0 merged 4 commits into
nitrojs:mainfrom
RihanArfan:feat/tasks-waituntil

Conversation

@RihanArfan
Copy link
Copy Markdown
Member

@RihanArfan RihanArfan commented Feb 16, 2026

🔗 Linked issue

❓ Type of change

  • 📖 Documentation (updates to the documentation, readme, or JSdoc annotations)
  • 🐞 Bug fix (a non-breaking change that fixes an issue)
  • 👌 Enhancement (improving an existing functionality like performance)
  • ✨ New feature (a non-breaking change that adds functionality)
  • 🧹 Chore (updates to the build process or auxiliary tools and libraries)
  • ⚠️ Breaking change (fix or feature that would cause existing functionality to change)

📚 Description

📝 Checklist

  • I have linked an issue or discussion.
  • I have updated the documentation accordingly.

TODO

@vercel
Copy link
Copy Markdown

vercel Bot commented Feb 16, 2026

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

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 16, 2026

📝 Walkthrough

Walkthrough

This PR updates the task scheduling system across multiple runtime presets to propagate a waitUntil context throughout task execution. The startScheduleRunner function signature is modified to accept an options object, and scheduled tasks now receive the server's lifecycle context for proper async completion handling.

Changes

Cohort / File(s) Summary
Core Task Scheduling Module
src/runtime/internal/task.ts
Updated startScheduleRunner signature to accept optional options with waitUntil, and modified task scheduling to pass waitUntil context to runTask for each scheduled task.
Runtime Preset Implementations
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/presets/_nitro/runtime/nitro-dev.ts
Updated all presets to pass waitUntil context from server lifecycle to startScheduleRunner via options object, enabling scheduled tasks to respect server shutdown lifecycle.
Task Execution Handlers
src/presets/vercel/runtime/cron-handler.ts, src/runtime/internal/routes/dev-tasks.ts
Modified cron and manual task execution routes to pass waitUntil context from request lifecycle to runCronTasks and runTask respectively.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The PR title follows conventional commits format with 'feat' type and descriptive scope 'tasks', clearly indicating the main enhancement of exposing req and waitUntil in context.
Description check ✅ Passed The description is related to the changeset as it uses the conventional PR template and marks 'Enhancement' as the type of change, aligning with the actual modifications that improve task scheduling with waitUntil context propagation.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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 and usage tips.

Comment thread src/runtime/internal/routes/dev-tasks.ts Outdated
Comment thread src/runtime/internal/task.ts Outdated
@pi0 pi0 marked this pull request as ready for review February 18, 2026 10:01
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Feb 18, 2026

Open in StackBlitz

npm i https://pkg.pr.new/nitrojs/nitro@4037

commit: 6845e06

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/runtime/internal/task.ts (1)

63-65: ⚠️ Potential issue | 🟡 Minor

scheduledTime captures server startup time, not the cron fire time

payload is created once when startScheduleRunner is called, so every cron invocation shares the same scheduledTime — the server start time. Move the payload construction inside the cron callback so each invocation records the actual scheduled time.

🐛 Proposed fix
-  const payload: TaskPayload = {
-    scheduledTime: Date.now(),
-  };
-
   for (const schedule of scheduledTasks) {
     new Cron(schedule.cron, async () => {
+      const payload: TaskPayload = {
+        scheduledTime: Date.now(),
+      };
       await Promise.all(
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/runtime/internal/task.ts` around lines 63 - 65, The payload object
(TaskPayload) is being created once when startScheduleRunner is called so
scheduledTime captures server startup time; to fix, move the construction of
const payload: TaskPayload = { scheduledTime: Date.now() } into the cron
callback inside startScheduleRunner (i.e., build a fresh payload for each cron
invocation) so each run sets scheduledTime at invocation time and use that
per-task payload when calling the task handler.
🧹 Nitpick comments (1)
src/runtime/internal/task.ts (1)

68-79: waitUntil is only passed to task context — the cron callback never registers itself with the server lifecycle

The schedule runner passes waitUntil into task context (so tasks may opt in), but the cron callback itself never calls waitUntil(tasksPromise). In runtimes with graceful-shutdown semantics (e.g., Cloudflare-style), scheduled tasks can be interrupted if the server receives a shutdown signal, because nothing registers the in-progress work at the server level. Consider forwarding the aggregate promise:

♻️ Suggested approach
     new Cron(schedule.cron, async () => {
-      await Promise.all(
-        schedule.tasks.map((name) =>
-          runTask(name, {
-            payload,
-            context: { waitUntil },
-          }).catch((error) => {
-            console.error(`Error while running scheduled task "${name}"`, error);
-          })
-        )
-      );
+      const tasksPromise = Promise.all(
+        schedule.tasks.map((name) =>
+          runTask(name, {
+            payload,
+            context: { waitUntil },
+          }).catch((error) => {
+            console.error(`Error while running scheduled task "${name}"`, error);
+          })
+        )
+      );
+      waitUntil?.(tasksPromise);
+      await tasksPromise;
     });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/runtime/internal/task.ts` around lines 68 - 79, The cron callback starts
all scheduled runTask calls but never registers the aggregate work with the
lifecycle, so ongoing tasks can be terminated on shutdown; capture the
Promise.all result (e.g., tasksPromise = Promise.all(...)) and call
waitUntil(tasksPromise) from inside the Cron callback so the runtime knows about
the in-flight work; keep the existing per-task .catch logging but ensure you
pass the wrapped/aggregated promise to waitUntil after mapping schedule.tasks to
runTask(name, { payload, context: { waitUntil } }) so the Cron lifecycle is
properly awaited.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/runtime/internal/task.ts`:
- Around line 54-58: Update the TaskContext type to include an optional
waitUntil property with signature waitUntil?: (promise: Promise<unknown>) =>
void (modify the TaskContext interface in src/types/runtime/task.ts) and add
JSDoc to the startScheduleRunner function's options parameter documenting the
options object and the waitUntil callback behavior; ensure the
startScheduleRunner signature and any place that constructs TaskContext (where {
waitUntil } is passed) remain type-safe with the new optional property name
TaskContext.waitUntil.

---

Outside diff comments:
In `@src/runtime/internal/task.ts`:
- Around line 63-65: The payload object (TaskPayload) is being created once when
startScheduleRunner is called so scheduledTime captures server startup time; to
fix, move the construction of const payload: TaskPayload = { scheduledTime:
Date.now() } into the cron callback inside startScheduleRunner (i.e., build a
fresh payload for each cron invocation) so each run sets scheduledTime at
invocation time and use that per-task payload when calling the task handler.

---

Nitpick comments:
In `@src/runtime/internal/task.ts`:
- Around line 68-79: The cron callback starts all scheduled runTask calls but
never registers the aggregate work with the lifecycle, so ongoing tasks can be
terminated on shutdown; capture the Promise.all result (e.g., tasksPromise =
Promise.all(...)) and call waitUntil(tasksPromise) from inside the Cron callback
so the runtime knows about the in-flight work; keep the existing per-task .catch
logging but ensure you pass the wrapped/aggregated promise to waitUntil after
mapping schedule.tasks to runTask(name, { payload, context: { waitUntil } }) so
the Cron lifecycle is properly awaited.

Comment thread src/runtime/internal/task.ts
@pi0 pi0 merged commit 254ff34 into nitrojs:main Feb 18, 2026
10 of 11 checks passed
@RihanArfan RihanArfan deleted the feat/tasks-waituntil branch February 18, 2026 12:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants