fix(webapp,run-engine,core): drop the hidden debounce ceiling, fail fast on an unusable maxDelay - #4521
fix(webapp,run-engine,core): drop the hidden debounce ceiling, fail fast on an unusable maxDelay#4521matt-aitken wants to merge 12 commits into
Conversation
…ject windows that cannot debounce A debounced run is only pushed later while the new execution time stays inside maxDelay (or the server maximum) measured from the first trigger, so the room to push is the gap between the two. A delay at or above that ceiling meant the first extension was already out of bounds: every trigger created its own run, with no error and nothing on the run to show the debounce had been ignored. The default ceiling moves from 1 hour to 24 hours, and a delay that leaves no room is now rejected at trigger time with a message naming both values and how to fix them. debounce.delay must also be a duration rather than a date, since it is re-applied on every extension.
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughThe change removes the default one-hour debounce ceiling. An unset server ceiling allows matching triggers to continue extending a run. Trigger-level 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
…ast on an unusable maxDelay The engine applied a server-side ceiling on how long a debounced run could be pushed back, defaulting to an hour and documented nowhere. Any delay at or above it could never push its run, so every trigger created its own run with no error and nothing on the run to show the debounce key had been ignored. The ceiling is now unset by default, so a key keeps collapsing triggers for as long as they arrive and maxDelay is the only bound. Self-hosters can still set one. Callers who pass a maxDelay that is not longer than their delay hit the same dead end, so that pair is rejected at trigger time rather than silently doing nothing.
@trigger.dev/build
trigger.dev
@trigger.dev/core
@trigger.dev/python
@trigger.dev/react-hooks
@trigger.dev/redis-worker
@trigger.dev/rsc
@trigger.dev/schema-to-json
@trigger.dev/sdk
commit: |
…ocument the duration grammar An empty string passed as maxDelay was falsy everywhere it was checked, so it read as no ceiling at all rather than as the invalid value it is. The server ceiling now also rejects zero and negative values at startup, and the duration grammar in the errors and JSDoc lists the hr suffix and compound forms that the parser has always accepted.
Validation only looked at a caller-supplied maxDelay, so a deployment that configures a server ceiling kept the original silent failure: a delay at or above it accepted the trigger and then created a run per trigger. The check now runs against the effective ceiling, whichever of the two applies, and a delay given as a date is rejected as well since the value is re-applied on every push and an absolute date can never work.
…ation z.coerce turns an empty string into 0, so a deployment that templates the variable without a value would have failed the new positive check and refused to boot. Reuse the file's existing blank-normalising pattern so absent, empty and whitespace all mean no ceiling, while a value that is actually set still has to be greater than zero.
…forced limit A trigger that sets maxDelay uses that value even when it is longer than the configured ceiling, so the setting bounds only the triggers that omit it. Say so where an operator reads it.
…a boot failure Zero was previously a legal value meaning the window closes on the first push, so rejecting it would stop an existing deployment from starting after an upgrade. Accepting it as a real ceiling is worse still, since the trigger-time check would then reject every debounced trigger. Zero and blank now both mean no ceiling, which keeps the setting switchable off and leaves negatives and garbage rejected. Also note in the docs that a trigger omitting maxDelay now has no bound at all, where it previously fell back to the built-in ceiling.
The only packages change here is JSDoc, so a changeset would file a server-side behaviour fix under the core package changelog, where upgrading the package does nothing for it.
…d run is pushed back With no ceiling, a continuously triggered key holds its run indefinitely, and triggerAndWait parents block on that run's waitpoint for the whole time, holding their concurrency with it.
…nbounded The fallback for an unparseable maxDelay is the server ceiling, which is now normally unset, so the old log line claimed a bound that no longer exists. Name the real outcome instead.
Debouncing with a
delaylonger than an hour did nothing at all.The engine applied a server-side ceiling on how long a debounced run could be pushed back, measured from the run's
createdAtand defaulting to one hour. A run is only pushed back while its new execution time stays inside that ceiling, so adelayat or above it could never push anything: the waiting run was released, the trigger started its own run, and the next trigger repeated it. Adelay: "12h"produced one run per trigger, each correctly delayed by 12h, with no error raised and nothing on the run to show the debounce key had been ignored.The ceiling is now unset by default. A debounce key with no
maxDelaykeeps collapsing triggers for as long as they keep arriving, which is what the docs have always described. Self-hosters who want a bound can still setRUN_ENGINE_MAXIMUM_DEBOUNCE_DURATION_MS.That has a consequence worth stating plainly, so the docs now carry a warning for it: with no
maxDelay, a continuously triggered key never executes. SetmaxDelaywhen the work has to happen eventually.Failing fast on an unusable
maxDelay. A caller who setsmaxDelayno longer than theirdelayhits exactly the dead end described above, so that pair is now rejected at trigger time instead of silently behaving as if no debounce were set:An unparseable
maxDelayis rejected too, rather than quietly falling back to no bound at all, and so is adelaygiven as a date rather than a duration, which could never work because the value is re-applied on every push.The same check runs against a configured server ceiling, so a self-hosted deployment that sets
RUN_ENGINE_MAXIMUM_DEBOUNCE_DURATION_MSgets the error rather than the silent failure this PR is about. With nomaxDelayand no configured ceiling, which is the default, there is nothing to conflict with and nothing is rejected.The docs, the
TriggerOptionsJSDoc and the engine option all now state that the room available to push is the gap betweendelayandmaxDelay. The run engine suite gains the case that motivated this: four triggers on one key with a 12h delay now collapse to a single run.