Skip to content

Commit 435f410

Browse files
committed
fix(webapp): treat a zero debounce ceiling as no ceiling rather than 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.
1 parent 373898c commit 435f410

2 files changed

Lines changed: 16 additions & 9 deletions

File tree

apps/webapp/app/env.server.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -114,11 +114,17 @@ const OptionalIntEnv = z.preprocess(
114114
z.coerce.number().int().optional()
115115
);
116116

117-
/** As {@link OptionalIntEnv}, but a value that is set must be greater than zero. */
118-
const OptionalPositiveIntEnv = z.preprocess(
119-
(v) => (typeof v === "string" && v.trim() === "" ? undefined : v),
120-
z.coerce.number().int().positive().optional()
121-
);
117+
/**
118+
* Optional int env var for a limit that can be switched off. Blank, whitespace and `0` all mean
119+
* "no limit" and normalise to undefined; anything else that is set must be greater than zero.
120+
*/
121+
const OptionalLimitEnv = z.preprocess((v) => {
122+
if (typeof v === "string" && (v.trim() === "" || Number(v.trim()) === 0)) {
123+
return undefined;
124+
}
125+
126+
return v === 0 ? undefined : v;
127+
}, z.coerce.number().int().positive().optional());
122128

123129
const EnvironmentSchema = z
124130
.object({
@@ -1047,9 +1053,9 @@ const EnvironmentSchema = z
10471053
* bound. Setting this applies a ceiling to every debounced run that does not carry its own
10481054
* `maxDelay`, and any `delay` at or above it is rejected at trigger time. It is a default
10491055
* rather than an enforced limit: a trigger that sets `maxDelay` uses that value even when it
1050-
* is longer than this.
1056+
* is longer than this. `0` and blank both mean no ceiling.
10511057
*/
1052-
RUN_ENGINE_MAXIMUM_DEBOUNCE_DURATION_MS: OptionalPositiveIntEnv,
1058+
RUN_ENGINE_MAXIMUM_DEBOUNCE_DURATION_MS: OptionalLimitEnv,
10531059

10541060
/**
10551061
* Bucket size in milliseconds used to quantize the newly computed `delayUntil`

docs/triggering.mdx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -933,8 +933,9 @@ Keep `delay` well below `maxDelay`. A run is only pushed back while its new exec
933933
<Note>
934934
The `maxDelay` value is evaluated from each trigger call, not stored with the original run. This
935935
means if you pass different `maxDelay` values for the same debounce key, each trigger uses its own
936-
`maxDelay` to check against the original run's creation time. For consistent behavior, use the
937-
same `maxDelay` value for all triggers with the same debounce key.
936+
`maxDelay` to check against the original run's creation time. A trigger that omits `maxDelay`
937+
has no bound at all, so a single call without it can push the run past the limit the other calls
938+
set. Use the same `maxDelay` value for every trigger with the same debounce key.
938939
</Note>
939940

940941
**Leading vs Trailing mode:**

0 commit comments

Comments
 (0)