Skip to content

Conversation

ericallam
Copy link
Member

@ericallam ericallam commented Sep 16, 2025

Prevent uncaught errors in the onSuccess, onComplete, and onFailure lifecycle hooks from failing attempts/runs.

Deprecated the onStart lifecycle hook (which only fires before the run function on the first attempt). Replaced with onStartAttempt that fires before the run function on every attempt:

export const taskWithOnStartAttempt = task({
  id: "task-with-on-start-attempt",
  onStartAttempt: async ({ payload, ctx }) => {
    //...
  },
  run: async (payload: any, { ctx }) => {
    //...
  },
});

// Default a global lifecycle hook using tasks
tasks.onStartAttempt(({ ctx, payload, task }) => {
  console.log(
    `Run ${ctx.run.id} started on task ${task} attempt ${ctx.run.attempt.number}`,
    ctx.run
  );
});

If you want to execute code before just the first attempt, you can use the onStartAttempt function and check ctx.run.attempt.number === 1:

export const taskWithOnStartAttempt = task({
  id: "task-with-on-start-attempt",
  onStartAttempt: async ({ payload, ctx }) => {
    if (ctx.run.attempt.number === 1) {
      console.log("Run started on attempt 1", ctx.run);
    }
  },
});

Copy link

changeset-bot bot commented Sep 16, 2025

🦋 Changeset detected

Latest commit: 6984903

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 23 packages
Name Type
@trigger.dev/sdk Minor
@trigger.dev/python Minor
d3-chat Patch
references-d3-openai-agents Patch
references-nextjs-realtime Patch
@trigger.dev/build Minor
@trigger.dev/core Minor
@trigger.dev/react-hooks Minor
@trigger.dev/redis-worker Minor
@trigger.dev/rsc Minor
@trigger.dev/schema-to-json Minor
@trigger.dev/database Minor
@trigger.dev/otlp-importer Minor
trigger.dev Minor
@internal/cache Patch
@internal/clickhouse Patch
@internal/redis Patch
@internal/replication Patch
@internal/run-engine Patch
@internal/schedule-engine Patch
@internal/testcontainers Patch
@internal/tracing Patch
@internal/zod-worker Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link
Contributor

coderabbitai bot commented Sep 16, 2025

Walkthrough

Introduces a new lifecycle hook, onStartAttempt, which runs before every task attempt; onStart is retained but deprecated and now only fires before the first attempt. Documentation and examples were updated to prefer global hooks in init.ts, deprecate per-task init/cleanup, and show how to detect the first attempt via ctx.run.attempt.number. Core types, lifecycle manager, and LifecycleHooksAPI gained APIs to register and retrieve global and per-task start-attempt hooks. TaskExecutor invokes start-attempt hooks (including on the initial attempt), aggregates global init results with task init results, and no longer propagates errors from onSuccess/onFailure/onComplete hooks. SDK and shared code expose tasks.onStartAttempt and per-task onStartAttempt; UI mapping and tests for ordering and hook-error semantics were added. A trailing newline was added to one package.json.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The PR description clearly documents the behavioral change and provides useful code examples for onStartAttempt, but it does not follow the repository's required template: it is missing the "Closes #" line, the ✅ checklist, a "Testing" section describing how the changes were validated, and a short "Changelog" entry (and screenshots where applicable). Please update the PR description to follow the repository template by adding "Closes #" if applicable, completing the checklist, providing a "Testing" section with steps/commands or test names used to validate the change, and adding a short "Changelog" summary (and screenshots or artifacts if useful); also include any migration/compatibility guidance for users about the onStart → onStartAttempt deprecation.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed The PR title "feat(sdk): replace onStart lifecycle hook with onStartAttempt" is concise, follows conventional-commit style, and accurately summarizes the primary change (deprecating onStart and introducing onStartAttempt) reflected across docs, core types, lifecycle manager, and SDK hooks, so a reviewer scanning history will quickly understand the main intent.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch ea-branch-88

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


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.

Copy link
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: 2

🧹 Nitpick comments (7)
.changeset/tiny-carrots-rest.md (4)

2-3: Include all affected packages in the changeset

Core types and APIs were added; ensure @trigger.dev/core (and any other published packages touched) receive a bump in this PR’s changesets, not just @trigger.dev/sdk.


20-27: Clarify file location for global hooks

Docs should state that global lifecycle hooks belong in trigger.config.ts per established guidance.

Apply this doc tweak:

-// Default a global lifecycle hook using tasks
+// Default a global lifecycle hook using tasks (in trigger.config.ts)
 tasks.onStartAttempt(({ ctx, payload, task }) => {

31-40: Code-fence filename syntax may not render

```ts /trigger/on-start-attempt.ts might not be recognized by your MDX tooling. Prefer title= or a preceding caption.


5-5: Specify logging/telemetry behavior for swallowed errors

If onSuccess/onComplete/onFailure errors no longer fail runs, note that they’re still captured in logs/metrics.

packages/core/src/v3/lifecycle-hooks-api.ts (1)

7-39: Re-export full StartAttempt types for consistency

You currently export only AnyOnStartAttemptHookFunction. Re-export OnStartAttemptHookFunction and TaskStartAttemptHookParams like other hooks to aid typing.

 export type {
   OnInitHookFunction,
   AnyOnInitHookFunction,
   RegisteredHookFunction,
   TaskInitHookParams,
   TaskStartHookParams,
   OnStartHookFunction,
   AnyOnStartHookFunction,
+  // StartAttempt
+  OnStartAttemptHookFunction,
+  TaskStartAttemptHookParams,
   TaskFailureHookParams,
   AnyOnFailureHookFunction,
   TaskSuccessHookParams,
   AnyOnSuccessHookFunction,
   TaskCompleteHookParams,
   AnyOnCompleteHookFunction,
   TaskWaitHookParams,
   AnyOnWaitHookFunction,
   TaskResumeHookParams,
   AnyOnResumeHookFunction,
   TaskCatchErrorHookParams,
   AnyOnCatchErrorHookFunction,
   TaskCompleteResult,
   TaskMiddlewareHookParams,
   AnyOnMiddlewareHookFunction,
   OnMiddlewareHookFunction,
   OnCleanupHookFunction,
   AnyOnCleanupHookFunction,
   TaskCleanupHookParams,
   TaskWait,
   TaskCancelHookParams,
   OnCancelHookFunction,
   AnyOnCancelHookFunction,
   AnyOnStartAttemptHookFunction,
 } from "./lifecycleHooks/types.js";
packages/core/src/v3/types/tasks.ts (1)

338-349: Consider clarifying the deprecation timeline for onStart.

While the deprecation notice directs users to onStartAttempt, consider adding information about when onStart will be removed to help users plan their migration.

Consider enhancing the deprecation notice:

   /**
    * onStart is called the first time a task is executed in a run (not before every retry)
    *
-   * @deprecated Use onStartAttempt instead
+   * @deprecated Use onStartAttempt instead. This will be removed in v5.0.0
    */
docs/tasks/overview.mdx (1)

359-362: Consider documenting where these suppressed errors are visible in the dashboard.

The documentation mentions that errors in onSuccess, onComplete, and onFailure are ignored but visible in the dashboard. Consider adding more specific information about where users can find these errors (e.g., in the run details, logs panel, etc.).

Would you like me to suggest more specific documentation about where these errors appear in the dashboard UI?

Also applies to: 390-393, 421-424

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 501a383 and 6170b3d.

⛔ Files ignored due to path filters (1)
  • references/hello-world/src/trigger/example.ts is excluded by !references/**
📒 Files selected for processing (14)
  • .changeset/tiny-carrots-rest.md (1 hunks)
  • apps/webapp/app/components/runs/v3/RunIcon.tsx (1 hunks)
  • docs/tasks/overview.mdx (9 hunks)
  • packages/cli-v3/package.json (1 hunks)
  • packages/core/src/v3/lifecycle-hooks-api.ts (1 hunks)
  • packages/core/src/v3/lifecycleHooks/index.ts (2 hunks)
  • packages/core/src/v3/lifecycleHooks/manager.ts (4 hunks)
  • packages/core/src/v3/lifecycleHooks/types.ts (2 hunks)
  • packages/core/src/v3/types/tasks.ts (4 hunks)
  • packages/core/src/v3/workers/taskExecutor.ts (8 hunks)
  • packages/core/test/taskExecutor.test.ts (2 hunks)
  • packages/trigger-sdk/src/v3/hooks.ts (2 hunks)
  • packages/trigger-sdk/src/v3/shared.ts (2 hunks)
  • packages/trigger-sdk/src/v3/tasks.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Always prefer using isomorphic code like fetch, ReadableStream, etc. instead of Node.js specific code
For TypeScript, we usually use types over interfaces
Avoid enums
No default exports, use function declarations

Files:

  • packages/core/src/v3/lifecycle-hooks-api.ts
  • apps/webapp/app/components/runs/v3/RunIcon.tsx
  • packages/trigger-sdk/src/v3/shared.ts
  • packages/trigger-sdk/src/v3/tasks.ts
  • packages/core/src/v3/lifecycleHooks/types.ts
  • packages/core/src/v3/lifecycleHooks/index.ts
  • packages/core/test/taskExecutor.test.ts
  • packages/core/src/v3/types/tasks.ts
  • packages/trigger-sdk/src/v3/hooks.ts
  • packages/core/src/v3/workers/taskExecutor.ts
  • packages/core/src/v3/lifecycleHooks/manager.ts
{packages/core,apps/webapp}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

We use zod a lot in packages/core and in the webapp

Files:

  • packages/core/src/v3/lifecycle-hooks-api.ts
  • apps/webapp/app/components/runs/v3/RunIcon.tsx
  • packages/core/src/v3/lifecycleHooks/types.ts
  • packages/core/src/v3/lifecycleHooks/index.ts
  • packages/core/test/taskExecutor.test.ts
  • packages/core/src/v3/types/tasks.ts
  • packages/core/src/v3/workers/taskExecutor.ts
  • packages/core/src/v3/lifecycleHooks/manager.ts
apps/webapp/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

When importing from @trigger.dev/core in the webapp, never import the root package path; always use one of the documented subpath exports from @trigger.dev/core’s package.json

Files:

  • apps/webapp/app/components/runs/v3/RunIcon.tsx
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Our tests are all vitest

Files:

  • packages/core/test/taskExecutor.test.ts
**/*.{test,spec}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{test,spec}.{ts,tsx,js,jsx}: Unit tests must use Vitest
Tests should avoid mocks or stubs and use helpers from @internal/testcontainers when Redis or Postgres are needed
Test files live beside the files under test and should use descriptive describe and it blocks

Files:

  • packages/core/test/taskExecutor.test.ts
🧠 Learnings (10)
📓 Common learnings
Learnt from: CR
PR: triggerdotdev/trigger.dev#0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-08-18T10:07:17.368Z
Learning: Applies to trigger.config.ts : Configure global task lifecycle hooks (onStart/onSuccess/onFailure) only within trigger.config.ts if needed, not within arbitrary files
📚 Learning: 2025-08-18T10:07:17.368Z
Learnt from: CR
PR: triggerdotdev/trigger.dev#0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-08-18T10:07:17.368Z
Learning: Applies to trigger.config.ts : Configure global task lifecycle hooks (onStart/onSuccess/onFailure) only within trigger.config.ts if needed, not within arbitrary files

Applied to files:

  • .changeset/tiny-carrots-rest.md
  • packages/trigger-sdk/src/v3/shared.ts
  • packages/trigger-sdk/src/v3/tasks.ts
  • packages/core/test/taskExecutor.test.ts
  • packages/core/src/v3/types/tasks.ts
  • docs/tasks/overview.mdx
  • packages/trigger-sdk/src/v3/hooks.ts
  • packages/core/src/v3/workers/taskExecutor.ts
📚 Learning: 2025-08-18T10:07:17.368Z
Learnt from: CR
PR: triggerdotdev/trigger.dev#0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-08-18T10:07:17.368Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Define tasks using task({ id, run, ... }) with a unique id per project

Applied to files:

  • .changeset/tiny-carrots-rest.md
  • packages/trigger-sdk/src/v3/tasks.ts
  • docs/tasks/overview.mdx
📚 Learning: 2025-08-18T10:07:17.368Z
Learnt from: CR
PR: triggerdotdev/trigger.dev#0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-08-18T10:07:17.368Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use triggerAndWait() only from within a task context (not from generic app code) and handle result.ok or use unwrap() with error handling

Applied to files:

  • .changeset/tiny-carrots-rest.md
  • packages/trigger-sdk/src/v3/tasks.ts
  • docs/tasks/overview.mdx
📚 Learning: 2025-08-18T10:07:17.368Z
Learnt from: CR
PR: triggerdotdev/trigger.dev#0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-08-18T10:07:17.368Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Do not use client.defineJob or any deprecated v2 patterns (e.g., eventTrigger) when defining tasks

Applied to files:

  • .changeset/tiny-carrots-rest.md
  • packages/trigger-sdk/src/v3/tasks.ts
  • docs/tasks/overview.mdx
📚 Learning: 2025-08-18T10:07:17.368Z
Learnt from: CR
PR: triggerdotdev/trigger.dev#0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-08-18T10:07:17.368Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Import Trigger.dev APIs from "trigger.dev/sdk/v3" when writing tasks or related utilities

Applied to files:

  • .changeset/tiny-carrots-rest.md
  • packages/trigger-sdk/src/v3/shared.ts
  • packages/trigger-sdk/src/v3/tasks.ts
📚 Learning: 2025-08-18T10:07:17.368Z
Learnt from: CR
PR: triggerdotdev/trigger.dev#0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-08-18T10:07:17.368Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use schedules.task(...) for scheduled (cron) tasks; do not implement schedules as plain task() with external cron logic

Applied to files:

  • packages/trigger-sdk/src/v3/tasks.ts
  • docs/tasks/overview.mdx
📚 Learning: 2025-08-18T10:07:17.368Z
Learnt from: CR
PR: triggerdotdev/trigger.dev#0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-08-18T10:07:17.368Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : When triggering a task multiple times in a loop from inside another task, use batchTrigger()/batchTriggerAndWait() instead of per-item trigger() calls

Applied to files:

  • packages/trigger-sdk/src/v3/tasks.ts
  • docs/tasks/overview.mdx
📚 Learning: 2025-08-18T10:07:17.368Z
Learnt from: CR
PR: triggerdotdev/trigger.dev#0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-08-18T10:07:17.368Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use schemaTask({ schema, run, ... }) to validate payloads when input validation is required

Applied to files:

  • packages/core/src/v3/types/tasks.ts
📚 Learning: 2025-08-18T10:07:17.368Z
Learnt from: CR
PR: triggerdotdev/trigger.dev#0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-08-18T10:07:17.368Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Export every task (including subtasks) defined with task(), schedules.task(), or schemaTask()

Applied to files:

  • docs/tasks/overview.mdx
🧬 Code graph analysis (7)
packages/trigger-sdk/src/v3/shared.ts (2)
packages/core/src/v3/lifecycle-hooks-api.ts (2)
  • lifecycleHooks (5-5)
  • AnyOnStartAttemptHookFunction (38-38)
packages/core/src/v3/lifecycleHooks/types.ts (1)
  • AnyOnStartAttemptHookFunction (47-47)
packages/core/src/v3/lifecycleHooks/index.ts (2)
packages/core/src/v3/lifecycleHooks/types.ts (3)
  • RegisterHookFunctionParams (182-185)
  • AnyOnStartAttemptHookFunction (47-47)
  • RegisteredHookFunction (187-191)
packages/core/src/v3/lifecycle-hooks-api.ts (2)
  • AnyOnStartAttemptHookFunction (38-38)
  • RegisteredHookFunction (10-10)
packages/core/test/taskExecutor.test.ts (3)
packages/core/src/v3/lifecycle-hooks-api.ts (1)
  • lifecycleHooks (5-5)
packages/core/src/v3/workers/taskExecutor.ts (12)
  • payload (364-416)
  • payload (418-454)
  • payload (682-782)
  • payload (784-849)
  • payload (851-916)
  • payload (918-928)
  • payload (930-994)
  • payload (996-1058)
  • payload (1060-1068)
  • payload (1070-1140)
  • payload (1352-1417)
  • result (1303-1350)
packages/core/src/v3/types/tasks.ts (1)
  • RunFnParams (89-96)
packages/core/src/v3/types/tasks.ts (3)
packages/trigger-sdk/src/v3/shared.ts (1)
  • Context (122-122)
packages/core/src/v3/lifecycleHooks/types.ts (2)
  • OnStartHookFunction (30-32)
  • OnStartAttemptHookFunction (43-45)
packages/core/src/v3/workers/taskExecutor.ts (11)
  • payload (364-416)
  • payload (418-454)
  • payload (682-782)
  • payload (784-849)
  • payload (851-916)
  • payload (918-928)
  • payload (930-994)
  • payload (996-1058)
  • payload (1060-1068)
  • payload (1070-1140)
  • payload (1352-1417)
packages/trigger-sdk/src/v3/hooks.ts (2)
packages/core/src/v3/lifecycle-hooks-api.ts (3)
  • AnyOnStartHookFunction (14-14)
  • AnyOnStartAttemptHookFunction (38-38)
  • lifecycleHooks (5-5)
packages/core/src/v3/lifecycleHooks/types.ts (2)
  • AnyOnStartHookFunction (34-34)
  • AnyOnStartAttemptHookFunction (47-47)
packages/core/src/v3/workers/taskExecutor.ts (5)
packages/core/src/utils.ts (1)
  • tryCatch (5-18)
packages/core/src/v3/schemas/common.ts (2)
  • TaskRunContext (407-417)
  • TaskRunContext (419-419)
packages/core/src/v3/lifecycle-hooks-api.ts (1)
  • lifecycleHooks (5-5)
packages/core/src/v3/run-timeline-metrics-api.ts (1)
  • runTimelineMetrics (5-5)
packages/core/src/v3/semanticInternalAttributes.ts (1)
  • SemanticInternalAttributes (1-64)
packages/core/src/v3/lifecycleHooks/manager.ts (1)
packages/core/src/v3/lifecycleHooks/types.ts (3)
  • RegisteredHookFunction (187-191)
  • AnyOnStartAttemptHookFunction (47-47)
  • RegisterHookFunctionParams (182-185)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (23)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
  • GitHub Check: typecheck / typecheck
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (22)
packages/cli-v3/package.json (1)

158-158: Trailing newline only — OK

No functional change. Safe to merge.

packages/core/src/v3/lifecycleHooks/types.ts (2)

36-48: New StartAttempt hook types look good

Shape matches intent (no init), return type aligned with other hooks.


285-294: Manager surface extended — ensure Noop/impl parity

Confirm NoopLifecycleHooksManager and the concrete manager implement these four new methods to avoid runtime undefined-method errors.

packages/trigger-sdk/src/v3/tasks.ts (1)

92-95: API addition looks good; deprecation marker is clear

tasks.onStartAttempt is exposed next to onStart with a deprecation note. Back-compat maintained.

packages/trigger-sdk/src/v3/shared.ts (1)

91-95: Per-task StartAttempt hook registration wired correctly — verified

Type cast and registration follow existing patterns: core types declare onStartAttempt (packages/core/src/v3/types/tasks.ts), lifecycle registration exists (packages/core/src/v3/lifecycleHooks/index.ts, manager.ts), and taskExecutor invokes the hook (packages/core/src/v3/workers/taskExecutor.ts); tests exercise hook ordering.

apps/webapp/app/components/runs/v3/RunIcon.tsx (1)

100-107: Approve — event name confirmed

Emitted span/icon is exactly "task-hook-onStartAttempt" (packages/core/src/v3/workers/taskExecutor.ts:1017, 1044) and RunIcon maps it (apps/webapp/app/components/runs/v3/RunIcon.tsx:100).

packages/core/test/taskExecutor.test.ts (2)

272-355: LGTM! The onStartAttempt test validates the new per-attempt lifecycle hook.

The test correctly:

  • Registers global and task-specific onStartAttempt hooks
  • Verifies hooks are called in the expected order (global-1, global-2, task)
  • Confirms each hook receives the correct payload
  • Validates that the init data is properly accessible in the run function

1334-1374: LGTM! Error suppression for onSuccess hooks is correctly implemented.

The test confirms that errors thrown in onSuccess hooks do not propagate and fail the run, which aligns with the documented behavior. The run completes successfully despite the hook error.

packages/core/src/v3/types/tasks.ts (2)

118-123: LGTM! StartAttemptFnParams type is consistent with existing patterns.

The new type follows the same structure as StartFnParams, providing context, optional init data, and the abort signal.


932-932: LGTM! TaskMetadataWithFunctions correctly includes the onStartAttempt function.

The type signature matches the expected pattern with payload and StartAttemptFnParams.

packages/core/src/v3/workers/taskExecutor.ts (6)

186-186: LGTM! The onStartAttempt hook is correctly invoked after the first-attempt check.

The placement ensures the hook runs on every attempt (including the first), which aligns with the documented behavior.


800-846: LGTM! Error suppression for onSuccess hooks is implemented correctly.

The removal of error propagation ensures that hook failures don't fail the run, matching the documented behavior and test expectations.


867-913: LGTM! Error suppression for onFailure hooks is consistent.

The implementation matches the onSuccess pattern, ensuring hook errors don't propagate.


1368-1414: LGTM! Error suppression for onComplete hooks follows the same pattern.

Consistent implementation across all three hook types (onSuccess, onFailure, onComplete).


694-773: LGTM! The init hook merging logic is well-implemented.

The implementation correctly:

  • Collects results from multiple global init hooks
  • Merges them with Object.assign
  • Allows task-specific init hooks to override global results
  • Preserves error propagation for init hooks (as they should fail the attempt)

996-1058: LGTM! The onStartAttempt implementation follows established patterns.

The new hook implementation:

  • Correctly retrieves both global and task-specific hooks
  • Executes them in the right order
  • Properly propagates errors (as start-attempt errors should fail the attempt)
  • Uses appropriate telemetry attributes
packages/core/src/v3/lifecycleHooks/index.ts (1)

85-104: LGTM! StartAttempt hook registration methods follow the established pattern.

The new methods correctly delegate to the lifecycle hooks manager and maintain consistency with existing hook registration patterns.

docs/tasks/overview.mdx (2)

250-294: LGTM! The onStartAttempt documentation is comprehensive and clear.

The documentation:

  • Clearly explains the new hook's purpose
  • Shows both per-task and global usage examples
  • Provides guidance on detecting the first attempt
  • Includes important error handling information

538-571: LGTM! The deprecation notice for onStart is clear and helpful.

The deprecated section:

  • Clearly marks the feature as deprecated
  • Provides migration guidance to onStartAttempt
  • Retains the documentation for existing users
  • Explains the key difference (once per run vs. per attempt)
packages/core/src/v3/lifecycleHooks/manager.ts (3)

17-18: LGTM: added import for AnyOnStartAttemptHookFunction

Import is correct and consistent with existing patterns.


27-35: LGTM: start-attempt hook maps added

Global and per‑task maps mirror existing start/init patterns. Single per‑task hook aligns with current design elsewhere.


142-171: LGTM: standard manager APIs for start-attempt hooks

Registration and retrieval methods follow established conventions (id generation, return shapes). No issues spotted.

Copy link
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

♻️ Duplicate comments (1)
packages/trigger-sdk/src/v3/hooks.ts (1)

45-56: Overload types corrected for onStartAttempt — nice.

The overloads now use AnyOnStartAttemptHookFunction; resolves the prior mismatch.

🧹 Nitpick comments (4)
packages/core/src/v3/types/tasks.ts (1)

344-350: Fix first-attempt check in docs comment.

Use ctx.run.attempt.number, not ctx.attempt.number.

- * You can detect the first attempt by checking `ctx.attempt.number === 1`.
+ * You can detect the first attempt by checking `ctx.run.attempt.number === 1`.
packages/trigger-sdk/src/v3/hooks.ts (1)

15-16: Re-export AnyOnStartAttemptHookFunction for API parity.

Other hook types are re-exported below; add this one too for consistency.

 export type {
   AnyOnStartHookFunction,
   TaskStartHookParams,
   OnStartHookFunction,
   AnyOnFailureHookFunction,
   AnyOnSuccessHookFunction,
   AnyOnCompleteHookFunction,
   TaskCompleteResult,
   AnyOnWaitHookFunction,
   AnyOnResumeHookFunction,
   AnyOnCatchErrorHookFunction,
   AnyOnMiddlewareHookFunction,
   AnyOnCancelHookFunction,
+  AnyOnStartAttemptHookFunction,
 };
docs/tasks/overview.mdx (2)

257-266: Rename code block path to match the feature.

The section is about onStartAttempt but the snippet is labeled /trigger/on-start.ts.

-```ts /trigger/on-start.ts
+```ts /trigger/on-start-attempt.ts
 export const taskWithOnStartAttempt = task({
   id: "task-with-on-start-attempt",
   onStartAttempt: async ({ payload, ctx }) => {
     //...
   },

380-388: Correct the earlier onComplete example (uses undefined result).

The snippet above in this section references result but destructures { payload, output, ctx }. Adjust to use a result param or update the example; consider:

onComplete: async ({ result, ctx }) => {
  if (result.ok) {
    console.log("Run succeeded", result.output);
  } else {
    console.log("Run failed", result.error);
  }
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 494b659 and 6984903.

⛔ Files ignored due to path filters (2)
  • docs/images/lifecycle-functions.png is excluded by !**/*.png
  • references/hello-world/src/trigger/example.ts is excluded by !references/**
📒 Files selected for processing (14)
  • .changeset/tiny-carrots-rest.md (1 hunks)
  • apps/webapp/app/components/runs/v3/RunIcon.tsx (1 hunks)
  • docs/tasks/overview.mdx (9 hunks)
  • packages/cli-v3/package.json (1 hunks)
  • packages/core/src/v3/lifecycle-hooks-api.ts (1 hunks)
  • packages/core/src/v3/lifecycleHooks/index.ts (2 hunks)
  • packages/core/src/v3/lifecycleHooks/manager.ts (4 hunks)
  • packages/core/src/v3/lifecycleHooks/types.ts (2 hunks)
  • packages/core/src/v3/types/tasks.ts (4 hunks)
  • packages/core/src/v3/workers/taskExecutor.ts (8 hunks)
  • packages/core/test/taskExecutor.test.ts (2 hunks)
  • packages/trigger-sdk/src/v3/hooks.ts (2 hunks)
  • packages/trigger-sdk/src/v3/shared.ts (2 hunks)
  • packages/trigger-sdk/src/v3/tasks.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (11)
  • .changeset/tiny-carrots-rest.md
  • packages/core/src/v3/lifecycle-hooks-api.ts
  • packages/cli-v3/package.json
  • apps/webapp/app/components/runs/v3/RunIcon.tsx
  • packages/core/src/v3/lifecycleHooks/types.ts
  • packages/core/src/v3/lifecycleHooks/manager.ts
  • packages/trigger-sdk/src/v3/tasks.ts
  • packages/core/src/v3/lifecycleHooks/index.ts
  • packages/trigger-sdk/src/v3/shared.ts
  • packages/core/test/taskExecutor.test.ts
  • packages/core/src/v3/workers/taskExecutor.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Always prefer using isomorphic code like fetch, ReadableStream, etc. instead of Node.js specific code
For TypeScript, we usually use types over interfaces
Avoid enums
No default exports, use function declarations

Files:

  • packages/trigger-sdk/src/v3/hooks.ts
  • packages/core/src/v3/types/tasks.ts
{packages/core,apps/webapp}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

We use zod a lot in packages/core and in the webapp

Files:

  • packages/core/src/v3/types/tasks.ts
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
PR: triggerdotdev/trigger.dev#0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-08-18T10:07:17.368Z
Learning: Applies to trigger.config.ts : Configure global task lifecycle hooks (onStart/onSuccess/onFailure) only within trigger.config.ts if needed, not within arbitrary files
📚 Learning: 2025-08-18T10:07:17.368Z
Learnt from: CR
PR: triggerdotdev/trigger.dev#0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-08-18T10:07:17.368Z
Learning: Applies to trigger.config.ts : Configure global task lifecycle hooks (onStart/onSuccess/onFailure) only within trigger.config.ts if needed, not within arbitrary files

Applied to files:

  • packages/trigger-sdk/src/v3/hooks.ts
  • packages/core/src/v3/types/tasks.ts
  • docs/tasks/overview.mdx
📚 Learning: 2025-08-18T10:07:17.368Z
Learnt from: CR
PR: triggerdotdev/trigger.dev#0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-08-18T10:07:17.368Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use schemaTask({ schema, run, ... }) to validate payloads when input validation is required

Applied to files:

  • packages/core/src/v3/types/tasks.ts
📚 Learning: 2025-08-18T10:07:17.368Z
Learnt from: CR
PR: triggerdotdev/trigger.dev#0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-08-18T10:07:17.368Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Define tasks using task({ id, run, ... }) with a unique id per project

Applied to files:

  • docs/tasks/overview.mdx
📚 Learning: 2025-08-18T10:07:17.368Z
Learnt from: CR
PR: triggerdotdev/trigger.dev#0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-08-18T10:07:17.368Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use schedules.task(...) for scheduled (cron) tasks; do not implement schedules as plain task() with external cron logic

Applied to files:

  • docs/tasks/overview.mdx
📚 Learning: 2025-08-18T10:07:17.368Z
Learnt from: CR
PR: triggerdotdev/trigger.dev#0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-08-18T10:07:17.368Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use triggerAndWait() only from within a task context (not from generic app code) and handle result.ok or use unwrap() with error handling

Applied to files:

  • docs/tasks/overview.mdx
📚 Learning: 2025-08-18T10:07:17.368Z
Learnt from: CR
PR: triggerdotdev/trigger.dev#0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-08-18T10:07:17.368Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : When triggering a task multiple times in a loop from inside another task, use batchTrigger()/batchTriggerAndWait() instead of per-item trigger() calls

Applied to files:

  • docs/tasks/overview.mdx
📚 Learning: 2025-08-18T10:07:17.368Z
Learnt from: CR
PR: triggerdotdev/trigger.dev#0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-08-18T10:07:17.368Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Export every task (including subtasks) defined with task(), schedules.task(), or schemaTask()

Applied to files:

  • docs/tasks/overview.mdx
📚 Learning: 2025-08-18T10:07:17.368Z
Learnt from: CR
PR: triggerdotdev/trigger.dev#0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-08-18T10:07:17.368Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Do not use client.defineJob or any deprecated v2 patterns (e.g., eventTrigger) when defining tasks

Applied to files:

  • docs/tasks/overview.mdx
🧬 Code graph analysis (2)
packages/trigger-sdk/src/v3/hooks.ts (2)
packages/core/src/v3/lifecycle-hooks-api.ts (2)
  • AnyOnStartAttemptHookFunction (38-38)
  • lifecycleHooks (5-5)
packages/core/src/v3/lifecycleHooks/types.ts (1)
  • AnyOnStartAttemptHookFunction (47-47)
packages/core/src/v3/types/tasks.ts (3)
packages/trigger-sdk/src/v3/shared.ts (1)
  • Context (122-122)
packages/core/src/v3/lifecycleHooks/types.ts (2)
  • OnStartHookFunction (30-32)
  • OnStartAttemptHookFunction (43-45)
packages/core/src/v3/workers/taskExecutor.ts (11)
  • payload (364-416)
  • payload (418-454)
  • payload (682-782)
  • payload (784-849)
  • payload (851-916)
  • payload (918-928)
  • payload (930-994)
  • payload (996-1058)
  • payload (1060-1068)
  • payload (1070-1140)
  • payload (1352-1417)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (23)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: typecheck / typecheck
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
  • GitHub Check: Analyze (javascript-typescript)

Comment on lines +118 to +124
export type StartAttemptFnParams = Prettify<{
ctx: Context;
init?: InitOutput;
/** Abort signal that is aborted when a task run exceeds it's maxDuration or if the task run is cancelled. Can be used to automatically cancel downstream requests */
signal: AbortSignal;
}>;

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

🧩 Analysis chain

Remove init from StartAttempt params (not passed at runtime).

#callOnStartAttemptFunctions() never supplies init, so exposing it here is misleading and can cause incorrect usage.

Apply:

-export type StartAttemptFnParams = Prettify<{
-  ctx: Context;
-  init?: InitOutput;
-  /** Abort signal that is aborted when a task run exceeds it's maxDuration or if the task run is cancelled. Can be used to automatically cancel downstream requests */
-  signal: AbortSignal;
-}>;
+export type StartAttemptFnParams = Prettify<{
+  ctx: Context;
+  /** Abort signal that is aborted when a task run exceeds it's maxDuration or if the task run is cancelled. Can be used to automatically cancel downstream requests */
+  signal: AbortSignal;
+}>;

Run to confirm no code depends on init in StartAttempt:


🏁 Script executed:

#!/bin/bash
rg -nP 'StartAttemptFnParams|onStartAttempt\(' -C3

Length of output: 3813


Remove init from StartAttemptFnParams (not passed at runtime).

onStartAttempt hooks are invoked without init; the exported type is misleading and should be removed.

Apply:

-export type StartAttemptFnParams = Prettify<{
-  ctx: Context;
-  init?: InitOutput;
-  /** Abort signal that is aborted when a task run exceeds it's maxDuration or if the task run is cancelled. Can be used to automatically cancel downstream requests */
-  signal: AbortSignal;
-}>;
+export type StartAttemptFnParams = Prettify<{
+  ctx: Context;
+  /** Abort signal that is aborted when a task run exceeds it's maxDuration or if the task run is cancelled. Can be used to automatically cancel downstream requests */
+  signal: AbortSignal;
+}>;

Files to update: packages/core/src/v3/types/tasks.ts (around lines ~118–124). Also update any SDK hook typings that re-export/reference this type (e.g., packages/trigger-sdk/src/v3/hooks.ts).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export type StartAttemptFnParams = Prettify<{
ctx: Context;
init?: InitOutput;
/** Abort signal that is aborted when a task run exceeds it's maxDuration or if the task run is cancelled. Can be used to automatically cancel downstream requests */
signal: AbortSignal;
}>;
export type StartAttemptFnParams = Prettify<{
ctx: Context;
/** Abort signal that is aborted when a task run exceeds it's maxDuration or if the task run is cancelled. Can be used to automatically cancel downstream requests */
signal: AbortSignal;
}>;
🤖 Prompt for AI Agents
In packages/core/src/v3/types/tasks.ts around lines 118–124, the exported
StartAttemptFnParams type incorrectly includes an optional init property which
is not provided at runtime for onStartAttempt hooks; remove the init property
from that type definition and update any downstream typings that re-export or
reference this type (for example packages/trigger-sdk/src/v3/hooks.ts) to use
the updated StartAttemptFnParams signature without init so the hook type
accurately reflects runtime parameters.

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