Skip to content

Comments

feat(debounce): add maxDelay option to limit total debounce time#2984

Merged
ericallam merged 2 commits intomainfrom
feat/debounce-max-delay
Feb 2, 2026
Merged

feat(debounce): add maxDelay option to limit total debounce time#2984
ericallam merged 2 commits intomainfrom
feat/debounce-max-delay

Conversation

@ericallam
Copy link
Member

@ericallam ericallam commented Feb 2, 2026

Summary

Adds a maxDelay option to the debounce feature that limits the maximum total time a debounced run can be delayed, regardless of how many subsequent triggers occur.

Linear issue: TRI-7234

Problem

With the current debounce implementation, continuous triggers can delay execution indefinitely. Each new trigger resets the delay window, meaning a run might never execute if triggers keep coming.

Example scenario: An AI chat application wants to summarize conversation threads. Messages come in frequently, and each message triggers a summarization task with debounce. Without maxDelay, the summary might never run if users keep chatting.

Solution

The new maxDelay option sets an upper bound on how long a debounced run can be delayed from its initial trigger time.

await summarizeConversation.trigger(payload, {
  debounce: {
    key: `conversation-${conversationId}`,
    delay: "10s",      // Wait 10s after each message before summarizing
    maxDelay: "5m",    // But always summarize within 5 minutes of first trigger
  },
});

How it works

Timeline example

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

Time    Event                           Run Status
─────────────────────────────────────────────────────────────
0s      Message 1 → trigger()           Run A created, delayed until 5s
2s      Message 2 → trigger()           Run A rescheduled to 7s
4s      Message 3 → trigger()           Run A rescheduled to 9s
6s      Message 4 → trigger()           Run A rescheduled to 11s
...
26s     Message 14 → trigger()          Run A rescheduled to 31s
28s     Message 15 → trigger()          ⚠️ Would reschedule to 33s, but that
                                        exceeds maxDelay (0s + 30s = 30s)
                                        → Run A executes, Run B created
30s     Message 16 → trigger()          Run B rescheduled to 35s
...

Behavior

  • When newDelayUntil > runCreatedAt + maxDelay, the system returns max_duration_exceeded
  • This allows the existing run to execute and creates a new run for subsequent triggers
  • If maxDelay is not specified, falls back to the server's global config (default: 1 hour)

Test plan

  • New unit tests for maxDelay behavior pass
  • Manual testing with hello-world reference project confirms maxDelay creates new runs at the expected time
  • Existing debounce tests continue to pass (backward compatible)

Open with Devin

Add a per-trigger maxDelay option that limits how long a debounced run
can be delayed. This ensures execution happens within a specified window
even with continuous triggers.

Use case: Summarizing AI conversation threads that need to stay relatively
up to date while still debouncing rapid message triggers.

refs TRI-7234
@changeset-bot
Copy link

changeset-bot bot commented Feb 2, 2026

🦋 Changeset detected

Latest commit: 2576a8e

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

This PR includes changesets to release 28 packages
Name Type
@trigger.dev/core Patch
@trigger.dev/sdk Patch
@trigger.dev/build Patch
trigger.dev Patch
@trigger.dev/python Patch
@trigger.dev/redis-worker Patch
@trigger.dev/schema-to-json Patch
@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/tsql Patch
@internal/zod-worker Patch
@internal/sdk-compat-tests Patch
d3-chat Patch
references-d3-openai-agents Patch
references-nextjs-realtime Patch
references-realtime-hooks-test Patch
references-realtime-streams Patch
references-telemetry Patch
@trigger.dev/react-hooks Patch
@trigger.dev/rsc Patch
@trigger.dev/database Patch
@trigger.dev/otlp-importer 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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 2, 2026

Walkthrough

This pull request adds a per-trigger maxDelay option to debounce configurations, updating type definitions and API schemas to include maxDelay?: string. It refactors duration parsing by introducing parseNaturalLanguageDurationInMs, updates the debounce system to use a computed per-trigger max duration with fallback to the global maxDebounceDurationMs, and adds tests validating per-trigger override, fallback to global config, and long maxDelay behavior.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 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%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically summarizes the main change: adding a maxDelay option to the debounce feature to limit total debounce time.
Description check ✅ Passed The PR description is comprehensive, well-structured, and covers all required sections with clear examples and test documentation.

✏️ 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
  • Commit unit tests in branch feat/debounce-max-delay

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.

@vibe-kanban-cloud
Copy link

Review Complete

Your review story is ready!

View Story

Comment !reviewfast on this PR to re-generate the story.

@ericallam ericallam marked this pull request as ready for review February 2, 2026 15:58
Copy link

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 4 additional flags.

Open in Devin Review

@ericallam ericallam merged commit b72cacc into main Feb 2, 2026
38 checks passed
@ericallam ericallam deleted the feat/debounce-max-delay branch February 2, 2026 20:15
@github-actions github-actions bot mentioned this pull request Jan 30, 2026
matt-aitken pushed a commit that referenced this pull request Feb 19, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and publish to npm
yourself or [setup this action to publish
automatically](https://github.com/changesets/action#with-publishing). If
you're not ready to do a release yet, that's fine, whenever you add more
changesets to main, this PR will be updated.


# Releases
## @trigger.dev/sdk@4.4.0

### Minor Changes

- Added `query.execute()` which lets you query your Trigger.dev data
using TRQL (Trigger Query Language) and returns results as typed JSON
rows or CSV. It supports configurable scope (environment, project, or
organization), time filtering via `period` or `from`/`to` ranges, and a
`format` option for JSON or CSV output.
([#3060](#3060))

    ```typescript
    import { query } from "@trigger.dev/sdk";
    import type { QueryTable } from "@trigger.dev/sdk";

    // Basic untyped query
const result = await query.execute("SELECT run_id, status FROM runs
LIMIT 10");

    // Type-safe query using QueryTable to pick specific columns
const typedResult = await query.execute<QueryTable<"runs", "run_id" |
"status" | "triggered_at">>(
      "SELECT run_id, status, triggered_at FROM runs LIMIT 10"
    );
    typedResult.results.forEach((row) => {
      console.log(row.run_id, row.status); // Fully typed
    });

    // Aggregation query with inline types
const stats = await query.execute<{ status: string; count: number }>(
      "SELECT status, COUNT(*) as count FROM runs GROUP BY status",
      { scope: "project", period: "30d" }
    );

    // CSV export
    const csv = await query.execute("SELECT run_id, status FROM runs", {
      format: "csv",
      period: "7d",
    });
    console.log(csv.results); // Raw CSV string
    ```

### Patch Changes

- Add `maxDelay` option to debounce feature. This allows setting a
maximum time limit for how long a debounced run can be delayed, ensuring
execution happens within a specified window even with continuous
triggers.
([#2984](#2984))

    ```typescript
    await myTask.trigger(payload, {
      debounce: {
        key: "my-key",
        delay: "5s",
maxDelay: "30m", // Execute within 30 minutes regardless of continuous
triggers
      },
    });
    ```

- Aligned the SDK's `getRunIdForOptions` logic with the Core package to
handle semantic targets (`root`, `parent`) in root tasks.
([#2874](#2874))

- Export `AnyOnStartAttemptHookFunction` type to allow defining
`onStartAttempt` hooks for individual tasks.
([#2966](#2966))

- Fixed a minor issue in the deployment command on distinguishing
between local builds for the cloud vs local builds for self-hosting
setups.
([#3070](#3070))

-   Updated dependencies:
    -   `@trigger.dev/core@4.4.0`

## @trigger.dev/build@4.4.0

### Patch Changes

-   Updated dependencies:
    -   `@trigger.dev/core@4.4.0`

## trigger.dev@4.4.0

### Patch Changes

- Fix runner getting stuck indefinitely when `execute()` is called on a
dead child process.
([#2978](#2978))
- Add optional `timeoutInSeconds` parameter to the
`wait_for_run_to_complete` MCP tool. Defaults to 60 seconds. If the run
doesn't complete within the timeout, the current state of the run is
returned instead of waiting indefinitely.
([#3035](#3035))
- Fixed a minor issue in the deployment command on distinguishing
between local builds for the cloud vs local builds for self-hosting
setups.
([#3070](#3070))
-   Updated dependencies:
    -   `@trigger.dev/core@4.4.0`
    -   `@trigger.dev/build@4.4.0`
    -   `@trigger.dev/schema-to-json@4.4.0`

## @trigger.dev/core@4.4.0

### Patch Changes

- Add `maxDelay` option to debounce feature. This allows setting a
maximum time limit for how long a debounced run can be delayed, ensuring
execution happens within a specified window even with continuous
triggers.
([#2984](#2984))

    ```typescript
    await myTask.trigger(payload, {
      debounce: {
        key: "my-key",
        delay: "5s",
maxDelay: "30m", // Execute within 30 minutes regardless of continuous
triggers
      },
    });
    ```

- Fixed a minor issue in the deployment command on distinguishing
between local builds for the cloud vs local builds for self-hosting
setups.
([#3070](#3070))

- fix: vendor superjson to fix ESM/CJS compatibility
([#2949](#2949))

Bundle superjson during build to avoid `ERR_REQUIRE_ESM` errors on
Node.js versions that don't support `require(ESM)` by default (&lt;
22.12.0) and AWS Lambda which intentionally disables it.

- Add Vercel integration support to API schemas: `commitSHA` and
`integrationDeployments` on deployment responses, and `source` field for
environment variable imports.
([#2994](#2994))

## @trigger.dev/python@4.4.0

### Patch Changes

-   Updated dependencies:
    -   `@trigger.dev/core@4.4.0`
    -   `@trigger.dev/sdk@4.4.0`
    -   `@trigger.dev/build@4.4.0`

## @trigger.dev/react-hooks@4.4.0

### Patch Changes

- Fix `onComplete` callback firing prematurely when the realtime stream
disconnects before the run finishes.
([#2929](#2929))
-   Updated dependencies:
    -   `@trigger.dev/core@4.4.0`

## @trigger.dev/redis-worker@4.4.0

### Patch Changes

-   Updated dependencies:
    -   `@trigger.dev/core@4.4.0`

## @trigger.dev/rsc@4.4.0

### Patch Changes

-   Updated dependencies:
    -   `@trigger.dev/core@4.4.0`

## @trigger.dev/schema-to-json@4.4.0

### Patch Changes

-   Updated dependencies:
    -   `@trigger.dev/core@4.4.0`

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
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