Skip to content

Commit fb4138a

Browse files
committed
better delay calculations
1 parent 96680f0 commit fb4138a

File tree

1 file changed

+44
-26
lines changed

1 file changed

+44
-26
lines changed

internal-packages/run-engine/src/engine/systems/debounceSystem.ts

Lines changed: 44 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -216,10 +216,13 @@ export class DebounceSystem {
216216

217217
// Timed out waiting - the other server may have failed
218218
// Delete the stale pending key and return "new"
219-
this.$.logger.warn("waitForExistingRun: timed out waiting for pending claim, deleting stale key", {
220-
redisKey,
221-
debounceKey: debounce.key,
222-
});
219+
this.$.logger.warn(
220+
"waitForExistingRun: timed out waiting for pending claim, deleting stale key",
221+
{
222+
redisKey,
223+
debounceKey: debounce.key,
224+
}
225+
);
223226
await this.redis.del(redisKey);
224227
return { status: "new" };
225228
}
@@ -287,17 +290,15 @@ export class DebounceSystem {
287290
return { status: "new" };
288291
}
289292

290-
// Calculate new delay
291-
const delayMs = parseNaturalLanguageDuration(debounce.delay);
292-
if (!delayMs) {
293+
// Calculate new delay - parseNaturalLanguageDuration returns a Date (now + duration)
294+
const newDelayUntil = parseNaturalLanguageDuration(debounce.delay);
295+
if (!newDelayUntil) {
293296
this.$.logger.error("handleExistingRun: invalid delay duration", {
294297
delay: debounce.delay,
295298
});
296299
return { status: "new" };
297300
}
298301

299-
const newDelayUntil = new Date(Date.now() + delayMs.getTime() - Date.now());
300-
301302
// Check if max debounce duration would be exceeded
302303
const runCreatedAt = existingRun.createdAt;
303304
const maxDelayUntil = new Date(runCreatedAt.getTime() + this.maxDebounceDurationMs);
@@ -316,25 +317,42 @@ export class DebounceSystem {
316317
return { status: "max_duration_exceeded" };
317318
}
318319

319-
// Reschedule the delayed run
320-
await this.delayedRunSystem.rescheduleDelayedRun({
321-
runId: existingRunId,
322-
delayUntil: newDelayUntil,
323-
tx: prisma,
324-
});
320+
// Only reschedule if the new delay would push the run later
321+
// This ensures debounce always "pushes later", never earlier
322+
const currentDelayUntil = existingRun.delayUntil;
323+
const shouldReschedule = !currentDelayUntil || newDelayUntil > currentDelayUntil;
324+
325+
if (shouldReschedule) {
326+
// Reschedule the delayed run
327+
await this.delayedRunSystem.rescheduleDelayedRun({
328+
runId: existingRunId,
329+
delayUntil: newDelayUntil,
330+
tx: prisma,
331+
});
325332

326-
// Update Redis TTL
327-
const ttlMs = Math.max(
328-
newDelayUntil.getTime() - Date.now() + 60_000, // Add 1 minute buffer
329-
60_000
330-
);
331-
await this.redis.pexpire(redisKey, ttlMs);
333+
// Update Redis TTL
334+
const ttlMs = Math.max(
335+
newDelayUntil.getTime() - Date.now() + 60_000, // Add 1 minute buffer
336+
60_000
337+
);
338+
await this.redis.pexpire(redisKey, ttlMs);
332339

333-
this.$.logger.debug("handleExistingRun: rescheduled existing debounced run", {
334-
existingRunId,
335-
debounceKey: debounce.key,
336-
newDelayUntil,
337-
});
340+
this.$.logger.debug("handleExistingRun: rescheduled existing debounced run", {
341+
existingRunId,
342+
debounceKey: debounce.key,
343+
newDelayUntil,
344+
});
345+
} else {
346+
this.$.logger.debug(
347+
"handleExistingRun: skipping reschedule, new delay is not later than current",
348+
{
349+
existingRunId,
350+
debounceKey: debounce.key,
351+
currentDelayUntil,
352+
newDelayUntil,
353+
}
354+
);
355+
}
338356

339357
return {
340358
status: "existing",

0 commit comments

Comments
 (0)