Skip to content
Open
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
49 changes: 48 additions & 1 deletion docs/triggering.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -867,8 +867,9 @@ await myTask.trigger({ updated: "data" }, { debounce: { key: "user-123", delay:
The `debounce` option accepts:

- `key` - A unique string to identify the debounce group (scoped to the task)
- `delay` - Duration string specifying how long to delay (e.g., "5s", "1m", "30s")
- `delay` - Duration string specifying how long to delay. Supported units: `s` (seconds), `m` (minutes), `h`/`hr` (hours), `d` (days), `w` (weeks). Minimum is 1 second. Examples: `"5s"`, `"1m"`, `"2h30m"`
- `mode` - Optional. Controls which trigger's data is used: `"leading"` (default) or `"trailing"`
- `maxDelay` - Optional. Maximum total time from the first trigger before the run must execute. Uses the same duration format as `delay`

Comment on lines 869 to 873
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

Clarify maxDelay minimum/units to match debounce parser constraints.

Line 872 mentions the format but doesn’t call out the min 1s / unit limits, which can lead to unsupported values (e.g., ms). Consider adding the same constraints as delay.

📝 Suggested wording
- - `maxDelay` - Optional. Maximum total time from the first trigger before the run must execute. Uses the same duration format as `delay`
+ - `maxDelay` - Optional. Maximum total time from the first trigger before the run must execute. Uses the same duration format as `delay` (min 1s; units `s`, `m`, `h`/`hr`, `d`, `w`)
Based on learnings: In the debounce system (internal-packages/run-engine/src/engine/systems/debounceSystem.ts), millisecond delays are not supported. The minimum debounce delay is 1 second (1s). The parseNaturalLanguageDuration function supports w/d/hr/h/m/s units only.
📝 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
- `key` - A unique string to identify the debounce group (scoped to the task)
- `delay` - Duration string specifying how long to delay (e.g., "5s", "1m", "30s")
- `delay` - Duration string specifying how long to delay. Supported units: `s` (seconds), `m` (minutes), `h`/`hr` (hours), `d` (days), `w` (weeks). Minimum is 1 second. Examples: `"5s"`, `"1m"`, `"2h30m"`
- `mode` - Optional. Controls which trigger's data is used: `"leading"` (default) or `"trailing"`
- `maxDelay` - Optional. Maximum total time from the first trigger before the run must execute. Uses the same duration format as `delay`
- `key` - A unique string to identify the debounce group (scoped to the task)
- `delay` - Duration string specifying how long to delay. Supported units: `s` (seconds), `m` (minutes), `h`/`hr` (hours), `d` (days), `w` (weeks). Minimum is 1 second. Examples: `"5s"`, `"1m"`, `"2h30m"`
- `mode` - Optional. Controls which trigger's data is used: `"leading"` (default) or `"trailing"`
- `maxDelay` - Optional. Maximum total time from the first trigger before the run must execute. Uses the same duration format as `delay` (min 1s; units `s`, `m`, `h`/`hr`, `d`, `w`)
🤖 Prompt for AI Agents
In `@docs/triggering.mdx` around lines 869 - 873, Update the docs for the maxDelay
field to state the same unit/minimum constraints as delay: it uses the same
duration format as delay (supported units: w, d, hr/h, m, s), millisecond values
are not supported, and the minimum allowed value is 1s; reference the debounce
parser implementation (parseNaturalLanguageDuration in debounceSystem.ts) to
ensure wording matches its behavior and mention both `delay` and `maxDelay` by
name so readers know both fields share these constraints.

**How it works:**

Expand All @@ -877,6 +878,52 @@ The `debounce` option accepts:
3. Once no new triggers occur within the delay duration, the run executes
4. After the run starts executing, a new trigger with the same key will create a new run

**Limiting total delay with `maxDelay`:**

By default, continuous triggers can delay execution indefinitely. The `maxDelay` option sets an upper bound on the total delay from the first trigger, ensuring the run eventually executes even with constant activity.

```ts
await summarizeChat.trigger(
{ conversationId: "123" },
{
debounce: {
key: "conversation-123",
delay: "10s", // Wait 10s after each message
maxDelay: "5m", // But always run within 5 minutes of first trigger
},
}
);
```

This is useful for scenarios like:

- Summarizing AI chat threads that need periodic updates even during active conversations
- Syncing data that should happen regularly despite continuous changes
- Any case where you want debouncing but also guarantee timely execution

**Timeline example with `maxDelay`:**

Consider `delay: "5s"` and `maxDelay: "30s"` with triggers arriving every 2 seconds:

| Time | Event | Result |
| :--- | :--- | :--- |
| 0s | Trigger 1 | Run A created, scheduled for 5s |
| 2s | Trigger 2 | Run A rescheduled to 7s |
| 4s | Trigger 3 | Run A rescheduled to 9s |
| ... | ... | ... |
| 26s | Trigger 14 | Run A rescheduled to 31s |
| 28s | Trigger 15 | Would reschedule to 33s, but exceeds maxDelay (30s). Run A executes, Run B created |
| 30s | Trigger 16 | Run B rescheduled to 35s |

Without `maxDelay`, continuous triggers would prevent the run from ever executing. With `maxDelay: "30s"`, execution is guaranteed within 30 seconds of the first trigger.

<Note>
The `maxDelay` value is evaluated from each trigger call, not stored with the original run. This
means if you pass different `maxDelay` values for the same debounce key, each trigger uses its own
`maxDelay` to check against the original run's creation time. For consistent behavior, use the
same `maxDelay` value for all triggers with the same debounce key.
</Note>
Comment on lines 878 to +925

Choose a reason for hiding this comment

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

🔴 Documentation describes non-existent maxDelay debounce option

The documentation adds extensive coverage of a maxDelay option for debounce that does not exist in the SDK or API.

Click to expand

Analysis

The PR adds documentation for maxDelay as a user-configurable option in the debounce settings (lines 872, 881-925). However, examining the actual implementation:

  1. SDK Types (packages/core/src/v3/types/tasks.ts:922-948): The debounce option only accepts key, delay, and mode - no maxDelay:
debounce?: {
  key: string;
  delay: string;
  mode?: "leading" | "trailing";
};
  1. API Schema (packages/core/src/v3/schemas/api.ts:216-222): The Zod schema also only validates key, delay, and mode:
debounce: z.object({
  key: z.string().max(512),
  delay: z.string(),
  mode: z.enum(["leading", "trailing"]).optional(),
}).optional()
  1. Server-side Implementation (internal-packages/run-engine/src/engine/systems/debounceSystem.ts:16-31): The DebounceOptions type has no maxDelay field.

The maxDebounceDurationMs that exists in the codebase is a server-side configuration set via environment variable (RUN_ENGINE_MAXIMUM_DEBOUNCE_DURATION_MS), not a per-trigger option.

Impact

Users reading this documentation would attempt to use maxDelay in their trigger calls:

await myTask.trigger(payload, {
  debounce: {
    key: "my-key",
    delay: "10s",
    maxDelay: "5m",  // This will be silently ignored!
  }
});

Since the property isn't in the schema, it would be silently ignored, leading to unexpected behavior where the max delay feature doesn't work as documented.

(Refers to lines 872-925)

Open in Devin Review

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


**Leading vs Trailing mode:**

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