Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/deprecate-max-duration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@trigger.dev/core": patch
"@trigger.dev/sdk": patch
"trigger.dev": patch
---

Deprecate `maxDuration` in favor of `maxComputeSeconds` because it's clearer. The new `maxComputeSeconds` property better reflects that the limit is based on compute time (CPU time) rather than wall-clock time. The old `maxDuration` property is still supported for backwards compatibility but will show deprecation warnings.
4 changes: 2 additions & 2 deletions .claude/skills/trigger-dev-tasks/advanced-tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ In trailing mode, these options update with each trigger:
- `metadata` — run metadata
- `tags` — run tags (replaces existing)
- `maxAttempts` — retry attempts
- `maxDuration` — maximum compute time
- `maxComputeSeconds` — maximum compute time in seconds
- `machine` — machine preset

### Important Notes
Expand Down Expand Up @@ -274,7 +274,7 @@ export const resilientTask = task({
export const heavyTask = task({
id: "heavy-computation",
machine: { preset: "large-2x" }, // 8 vCPU, 16 GB RAM
maxDuration: 1800, // 30 minutes timeout
maxComputeSeconds: 1800, // 30 minutes timeout
run: async (payload, { ctx }) => {
// Resource-intensive computation
if (ctx.machine.preset === "large-2x") {
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/trigger-dev-tasks/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ export default defineConfig({
export default defineConfig({
// ... other config
defaultMachine: "large-1x", // Default machine for all tasks
maxDuration: 300, // Default max duration (seconds)
maxComputeSeconds: 300, // Default max compute time (seconds)
enableConsoleLogging: true, // Console logging in development
});
```
Expand Down
2 changes: 1 addition & 1 deletion apps/webapp/app/components/runs/v3/ReplayRunDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ function ReplayForm({
<FormError id={maxAttempts.errorId}>{maxAttempts.error}</FormError>
</InputGroup>
<InputGroup>
<Label variant="small">Max duration</Label>
<Label variant="small">Max compute time</Label>
<DurationPicker
name={maxDurationSeconds.name}
id={maxDurationSeconds.id}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -742,7 +742,7 @@ function StandardTaskForm({
<FormError id={maxAttempts.errorId}>{maxAttempts.error}</FormError>
</InputGroup>
<InputGroup>
<Label variant="small">Max duration</Label>
<Label variant="small">Max compute time</Label>
<DurationPicker
name={maxDurationSeconds.name}
id={maxDurationSeconds.id}
Expand Down Expand Up @@ -1318,7 +1318,7 @@ function ScheduledTaskForm({
</InputGroup>
<InputGroup>
<Label htmlFor={maxDurationSeconds.id} variant="small">
Max duration
Max compute time
</Label>
<DurationPicker
name={maxDurationSeconds.name}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -869,7 +869,7 @@ function RunBody({
</Property.Value>
</Property.Item>
<Property.Item>
<Property.Label>Max duration</Property.Label>
<Property.Label>Max compute time</Property.Label>
<Property.Value>
{run.maxDurationInSeconds
? `${run.maxDurationInSeconds}s (${formatDurationMilliseconds(
Expand Down
8 changes: 4 additions & 4 deletions docs/config/config-file.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -334,21 +334,21 @@ export default defineConfig({
});
```

## Max duration
## Max compute time

You can set the default `maxDuration` for all tasks in your project:
You can set the default `maxComputeSeconds` for all tasks in your project:

```ts trigger.config.ts
import { defineConfig } from "@trigger.dev/sdk";

export default defineConfig({
project: "<project ref>",
// Your other config settings...
maxDuration: 60, // 60 seconds
maxComputeSeconds: 60, // 60 seconds
});
```

See our [maxDuration guide](/runs/max-duration) for more information.
See our [maxComputeSeconds guide](/runs/max-duration) for more information.

## Process keep alive

Expand Down
78 changes: 41 additions & 37 deletions docs/runs/max-duration.mdx
Original file line number Diff line number Diff line change
@@ -1,35 +1,39 @@
---
title: "Max duration"
sidebarTitle: "Max duration"
description: "Set a maximum duration for a task to run."
title: "Max compute time"
sidebarTitle: "Max compute time"
description: "Set a maximum compute time limit for a task to run."
---

The `maxDuration` parameter sets a maximum compute time limit for tasks. When a task exceeds this duration, it will be automatically stopped. This helps prevent runaway tasks and manage compute resources effectively.
The `maxComputeSeconds` parameter sets a maximum compute time limit for tasks. When a task exceeds this duration, it will be automatically stopped. This helps prevent runaway tasks and manage compute resources effectively.

You must set a default maxDuration in your `trigger.config.ts` file, which will apply to all tasks unless overridden:
<Note>
`maxDuration` replaces the deprecated `maxComputeSeconds` parameter. Both work the same way, but we recommend using `maxDuration` for clarity.
Copy link
Contributor

Choose a reason for hiding this comment

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

🔴 Documentation note says the opposite of what's intended — claims maxDuration replaces maxComputeSeconds

The deprecation note in the documentation has the old and new names swapped, telling users the exact opposite of the PR's intent.

Details

At docs/runs/max-duration.mdx:10, the note reads:

`maxDuration` replaces the deprecated `maxComputeSeconds` parameter.

But the entire PR is about deprecating maxDuration in favor of maxComputeSeconds. The note should say:

`maxComputeSeconds` replaces the deprecated `maxDuration` parameter.

Impact: Users reading this documentation will be confused about which property to use — the note directly contradicts all other documentation and code changes in this PR.

Suggested change
`maxDuration` replaces the deprecated `maxComputeSeconds` parameter. Both work the same way, but we recommend using `maxDuration` for clarity.
`maxComputeSeconds` replaces the deprecated `maxDuration` parameter. Both work the same way, but we recommend using `maxComputeSeconds` for clarity.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

</Note>

You must set a default maxComputeSeconds in your `trigger.config.ts` file, which will apply to all tasks unless overridden:

```ts /config/trigger.config.ts
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 | 🟡 Minor

Use typescript code-fence tags in docs examples.

These fences use ts; the docs guideline requires typescript.

Proposed fix
-```ts /config/trigger.config.ts
+```typescript /config/trigger.config.ts
@@
-```ts /trigger/max-duration.ts
+```typescript /trigger/max-duration.ts
@@
-```ts /trigger/max-duration-task.ts
+```typescript /trigger/max-duration-task.ts
@@
-```ts /trigger/max-duration-task.ts
+```typescript /trigger/max-duration-task.ts
@@
-```ts /trigger/max-duration.ts
+```typescript /trigger/max-duration.ts
@@
-```ts /trigger/max-duration.ts
+```typescript /trigger/max-duration.ts
@@
-```ts /trigger/max-duration-task.ts
+```typescript /trigger/max-duration-task.ts

As per coding guidelines, Use language tags in code fences: typescript, bash, json.

Also applies to: 44-44, 66-66, 82-82, 98-98, 112-112, 129-129

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/runs/max-duration.mdx` at line 15, Replace the short `ts` code-fence
tags with the required `typescript` tag in the docs examples: update the fences
referencing `/config/trigger.config.ts`, `/trigger/max-duration.ts`, and
`/trigger/max-duration-task.ts` (and the repeated instances noted at lines 44,
66, 82, 98, 112, 129) so each opening fence reads ```typescript <path> instead
of ```ts <path>; ensure all matching closing fences remain unchanged.

import { defineConfig } from "@trigger.dev/sdk";

export default defineConfig({
project: "proj_gtcwttqhhtlasxgfuhxs",
maxDuration: 60, // 60 seconds or 1 minute
maxComputeSeconds: 60, // 60 seconds or 1 minute
});
```

<Note>
The minimum maxDuration is 5 seconds. If you want to avoid timeouts, set this value to a very large number of seconds.
The minimum maxComputeSeconds is 5 seconds. If you want to avoid timeouts, set this value to a very large number of seconds.
</Note>

You can set the `maxDuration` for a run in the following ways:
You can set the `maxComputeSeconds` for a run in the following ways:

- Across all your tasks in the [config](/config/config-file#max-duration)
- Across all your tasks in the [config](/config/config-file#max-compute-time)
- On a specific task
- On a specific run when you [trigger a task](/triggering#maxduration)
- On a specific run when you [trigger a task](/triggering#maxcomputeseconds)

## How it works

The `maxDuration` is set in seconds, and is compared to the CPU time elapsed since the start of a single execution (which we call [attempts](/runs#attempts)) of the task. The CPU time is the time that the task has been actively running on the CPU, and does not include time spent waiting during the following:
The `maxComputeSeconds` is set in seconds, and is compared to the CPU time elapsed since the start of a single execution (which we call [attempts](/runs#attempts)) of the task. The CPU time is the time that the task has been actively running on the CPU, and does not include time spent waiting during the following:

- `wait.for` calls
- `triggerAndWait` calls
Expand All @@ -40,9 +44,9 @@ You can inspect the CPU time of a task inside the run function with our `usage`
```ts /trigger/max-duration.ts
import { task, usage } from "@trigger.dev/sdk";

export const maxDurationTask = task({
export const maxComputeSecondsTask = task({
id: "max-duration-task",
maxDuration: 300, // 300 seconds or 5 minutes
maxComputeSeconds: 300, // 300 seconds or 5 minutes
run: async (payload: any, { ctx }) => {
let currentUsage = usage.getCurrent();

Expand All @@ -51,36 +55,36 @@ export const maxDurationTask = task({
});
```

The above value will be compared to the `maxDuration` you set. If the task exceeds the `maxDuration`, it will be stopped with the following error:
The above value will be compared to the `maxComputeSeconds` you set. If the task exceeds the `maxComputeSeconds`, it will be stopped with the following error:

![Max duration error](/runs/max-duration-error.png)

## Configuring for a task

You can set a `maxDuration` on a specific task:
You can set a `maxComputeSeconds` on a specific task:

```ts /trigger/max-duration-task.ts
import { task } from "@trigger.dev/sdk";

export const maxDurationTask = task({
export const maxComputeSecondsTask = task({
id: "max-duration-task",
maxDuration: 300, // 300 seconds or 5 minutes
maxComputeSeconds: 300, // 300 seconds or 5 minutes
run: async (payload: any, { ctx }) => {
//...
},
});
```

This will override the default `maxDuration` set in the config file. If you have a config file with a default `maxDuration` of 60 seconds, and you set a `maxDuration` of 300 seconds on a task, the task will run for 300 seconds.
This will override the default `maxComputeSeconds` set in the config file. If you have a config file with a default `maxComputeSeconds` of 60 seconds, and you set a `maxComputeSeconds` of 300 seconds on a task, the task will run for 300 seconds.

You can "turn off" the Max duration set in your config file for a specific task like so:

```ts /trigger/max-duration-task.ts
import { task, timeout } from "@trigger.dev/sdk";

export const maxDurationTask = task({
export const maxComputeSecondsTask = task({
id: "max-duration-task",
maxDuration: timeout.None, // No max duration
maxComputeSeconds: timeout.None, // No max duration
run: async (payload: any, { ctx }) => {
//...
},
Expand All @@ -89,51 +93,51 @@ export const maxDurationTask = task({

## Configuring for a run

You can set a `maxDuration` on a specific run when you trigger a task:
You can set a `maxComputeSeconds` on a specific run when you trigger a task:

```ts /trigger/max-duration.ts
import { maxDurationTask } from "./trigger/max-duration-task";
import { maxComputeSecondsTask } from "./trigger/max-duration-task";
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 | 🟡 Minor

Snippet import path is not runnable from the shown file location.

In /trigger/max-duration.ts, importing ./trigger/max-duration-task points to a nested directory. The sibling-file import should be ./max-duration-task.

Proposed fix
-import { maxComputeSecondsTask } from "./trigger/max-duration-task";
+import { maxComputeSecondsTask } from "./max-duration-task";
@@
-import { maxComputeSecondsTask } from "./trigger/max-duration-task";
+import { maxComputeSecondsTask } from "./max-duration-task";

As per coding guidelines, Code examples must be complete and runnable where possible.

Also applies to: 113-113

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/runs/max-duration.mdx` at line 99, The import path for the example
snippet is incorrect: update the import of maxComputeSecondsTask from
"./trigger/max-duration-task" to the sibling module "./max-duration-task" so the
snippet is runnable; locate the import statement that references
maxComputeSecondsTask and replace the nested "./trigger/max-duration-task"
module path with "./max-duration-task" (also update the duplicate occurrence
noted further down).


// Trigger the task with a maxDuration of 300 seconds
const run = await maxDurationTask.trigger(
// Trigger the task with a maxComputeSeconds of 300 seconds
const run = await maxComputeSecondsTask.trigger(
{ foo: "bar" },
{
maxDuration: 300, // 300 seconds or 5 minutes
maxComputeSeconds: 300, // 300 seconds or 5 minutes
}
);
```

You can also set the `maxDuration` to `timeout.None` to turn off the max duration for a specific run:
You can also set the `maxComputeSeconds` to `timeout.None` to turn off the max duration for a specific run:

```ts /trigger/max-duration.ts
import { maxDurationTask } from "./trigger/max-duration-task";
import { maxComputeSecondsTask } from "./trigger/max-duration-task";
import { timeout } from "@trigger.dev/sdk";

// Trigger the task with no maxDuration
const run = await maxDurationTask.trigger(
// Trigger the task with no maxComputeSeconds
const run = await maxComputeSecondsTask.trigger(
{ foo: "bar" },
{
maxDuration: timeout.None, // No max duration
maxComputeSeconds: timeout.None, // No max duration
}
);
```

## maxDuration in run context
## maxComputeSeconds in run context

You can access the `maxDuration` set for a run in the run context:
You can access the `maxComputeSeconds` set for a run in the run context:

```ts /trigger/max-duration-task.ts
import { task } from "@trigger.dev/sdk";

export const maxDurationTask = task({
export const maxComputeSecondsTask = task({
id: "max-duration-task",
maxDuration: 300, // 300 seconds or 5 minutes
maxComputeSeconds: 300, // 300 seconds or 5 minutes
run: async (payload: any, { ctx }) => {
console.log(ctx.run.maxDuration); // 300
console.log(ctx.run.maxComputeSeconds); // 300
Copy link
Contributor

Choose a reason for hiding this comment

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

🚩 Documentation references ctx.run.maxComputeSeconds but the runtime context schema likely still uses maxDuration

At docs/runs/max-duration.mdx:136, the docs show ctx.run.maxComputeSeconds as the way to access the value in the run context. However, the runtime context schemas at packages/core/src/v3/schemas/messages.ts:195 use maxDurationInSeconds, and no changes were made to the context/schemas in this PR. This means ctx.run.maxComputeSeconds likely doesn't exist at runtime — it's probably still ctx.run.maxDuration or ctx.run.maxDurationInSeconds. This documentation claim should be verified against the actual runtime context type.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

},
});
```

## maxDuration and lifecycle functions
## maxComputeSeconds and lifecycle functions

When a task run exceeds the `maxDuration`, the lifecycle functions `cleanup`, `onSuccess`, and `onFailure` will not be called.
When a task run exceeds the `maxComputeSeconds`, the lifecycle functions `cleanup`, `onSuccess`, and `onFailure` will not be called.
8 changes: 4 additions & 4 deletions docs/tasks/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -120,21 +120,21 @@ export const heavyTask = task({
});
```

### `maxDuration` option
### `maxComputeSeconds` option

By default tasks can execute indefinitely, which can be great! But you also might want to set a `maxDuration` to prevent a task from running too long. You can set the `maxDuration` on a task, and all runs of that task will be stopped if they exceed the duration.
By default tasks can execute indefinitely, which can be great! But you also might want to set a `maxComputeSeconds` to prevent a task from running too long. You can set the `maxComputeSeconds` on a task, and all runs of that task will be stopped if they exceed the duration.

```ts /trigger/long-task.ts
export const longTask = task({
id: "long-task",
maxDuration: 300, // 300 seconds or 5 minutes
maxComputeSeconds: 300, // 300 seconds or 5 minutes
run: async (payload: any, { ctx }) => {
//...
},
});
```

See our [maxDuration guide](/runs/max-duration) for more information.
See our [maxComputeSeconds guide](/runs/max-duration) for more information.

## Global lifecycle hooks

Expand Down
6 changes: 3 additions & 3 deletions docs/triggering.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -932,7 +932,7 @@ Without `maxDelay`, continuous triggers would prevent the run from ever executin

By default, debounce uses **leading mode** - the run executes with data from the **first** trigger.

With **trailing mode**, each subsequent trigger updates the run's data (payload, metadata, tags, maxAttempts, maxDuration, and machine), so the run executes with data from the **last** trigger:
With **trailing mode**, each subsequent trigger updates the run's data (payload, metadata, tags, maxAttempts, maxComputeSeconds, and machine), so the run executes with data from the **last** trigger:

```ts
// Leading mode (default): runs with first payload
Expand Down Expand Up @@ -1090,9 +1090,9 @@ View our [tags doc](/tags) for more information.

View our [metadata doc](/runs/metadata) for more information.

### `maxDuration`
### `maxComputeSeconds`

View our [maxDuration doc](/runs/max-duration) for more information.
View our [maxComputeSeconds doc](/runs/max-duration) for more information.

### `priority`

Expand Down
7 changes: 4 additions & 3 deletions packages/cli-v3/src/entryPoints/dev-index-worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,14 @@ if (config.retries?.default) {
});
}

// If the config has a maxDuration, we need to apply it to all tasks that don't have a maxDuration
if (typeof config.maxDuration === "number") {
// If the config has a maxComputeSeconds or maxDuration, we need to apply it to all tasks that don't have a maxDuration
const configMaxDuration = config.maxComputeSeconds ?? config.maxDuration;
if (typeof configMaxDuration === "number") {
tasks = tasks.map((task) => {
if (typeof task.maxDuration !== "number") {
return {
...task,
maxDuration: config.maxDuration,
maxDuration: configMaxDuration,
} satisfies TaskManifest;
}

Expand Down
7 changes: 4 additions & 3 deletions packages/cli-v3/src/entryPoints/managed-index-worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,14 @@ if (config.retries?.default) {
});
}

// If the config has a maxDuration, we need to apply it to all tasks that don't have a maxDuration
if (typeof config.maxDuration === "number") {
// If the config has a maxComputeSeconds or maxDuration, we need to apply it to all tasks that don't have a maxDuration
const configMaxDuration = config.maxComputeSeconds ?? config.maxDuration;
if (typeof configMaxDuration === "number") {
tasks = tasks.map((task) => {
if (typeof task.maxDuration !== "number") {
return {
...task,
maxDuration: config.maxDuration,
maxDuration: configMaxDuration,
} satisfies TaskManifest;
}

Expand Down
4 changes: 2 additions & 2 deletions packages/cli-v3/templates/examples/schedule.mjs.template
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ export const firstScheduledTask = schedules.task({
id: "first-scheduled-task",
// Every hour
cron: "0 * * * *",
// Set an optional maxDuration to prevent tasks from running indefinitely
maxDuration: 300, // Stop executing after 300 secs (5 mins) of compute
// Set an optional maxComputeSeconds to prevent tasks from running indefinitely
maxComputeSeconds: 300, // Stop executing after 300 secs (5 mins) of compute
run: async (payload, { ctx }) => {
// The payload contains the last run timestamp that you can use to check if this is the first run
// And calculate the time since the last run
Expand Down
4 changes: 2 additions & 2 deletions packages/cli-v3/templates/examples/schedule.ts.template
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ export const firstScheduledTask = schedules.task({
id: "first-scheduled-task",
// Every hour
cron: "0 * * * *",
// Set an optional maxDuration to prevent tasks from running indefinitely
maxDuration: 300, // Stop executing after 300 secs (5 mins) of compute
// Set an optional maxComputeSeconds to prevent tasks from running indefinitely
maxComputeSeconds: 300, // Stop executing after 300 secs (5 mins) of compute
run: async (payload, { ctx }) => {
// The payload contains the last run timestamp that you can use to check if this is the first run
// And calculate the time since the last run
Expand Down
4 changes: 2 additions & 2 deletions packages/cli-v3/templates/examples/simple.mjs.template
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { logger, task, wait } from "@trigger.dev/sdk/v3";

export const helloWorldTask = task({
id: "hello-world",
// Set an optional maxDuration to prevent tasks from running indefinitely
maxDuration: 300, // Stop executing after 300 secs (5 mins) of compute
// Set an optional maxComputeSeconds to prevent tasks from running indefinitely
maxComputeSeconds: 300, // Stop executing after 300 secs (5 mins) of compute
run: async (payload, { ctx }) => {
logger.log("Hello, world!", { payload, ctx });

Expand Down
4 changes: 2 additions & 2 deletions packages/cli-v3/templates/examples/simple.ts.template
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { logger, task, wait } from "@trigger.dev/sdk/v3";

export const helloWorldTask = task({
id: "hello-world",
// Set an optional maxDuration to prevent tasks from running indefinitely
maxDuration: 300, // Stop executing after 300 secs (5 mins) of compute
// Set an optional maxComputeSeconds to prevent tasks from running indefinitely
maxComputeSeconds: 300, // Stop executing after 300 secs (5 mins) of compute
run: async (payload: any, { ctx }) => {
logger.log("Hello, world!", { payload, ctx });

Expand Down
Loading