Skip to content

Commit 1a6a9ca

Browse files
authored
perf fix: calculateNextScheduledTimestamp speed improvement (#2099)
* Simulate "next steps" when calculating the next timestamp to prevent millions of iterations on dev schedues * Add additional tests * Fix typescript issue
1 parent 6cb57b8 commit 1a6a9ca

File tree

3 files changed

+477
-2
lines changed

3 files changed

+477
-2
lines changed

apps/webapp/app/v3/services/registerNextTaskScheduleInstance.server.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ export class RegisterNextTaskScheduleInstanceService extends BaseService {
2828
"task_schedule_generator_expression",
2929
instance.taskSchedule.generatorExpression
3030
);
31+
span.setAttribute(
32+
"last_scheduled_timestamp",
33+
instance.lastScheduledTimestamp?.toISOString() ?? new Date().toISOString()
34+
);
3135

3236
return calculateNextScheduledTimestamp(
3337
instance.taskSchedule.generatorExpression,

apps/webapp/app/v3/utils/calculateNextSchedule.server.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,33 @@ export function calculateNextScheduledTimestamp(
55
timezone: string | null,
66
lastScheduledTimestamp: Date = new Date()
77
) {
8+
const now = Date.now();
9+
810
let nextStep = calculateNextStep(schedule, timezone, lastScheduledTimestamp);
911

10-
while (nextStep.getTime() < Date.now()) {
11-
nextStep = calculateNextStep(schedule, timezone, nextStep);
12+
// If the next step is still in the past, we might need to skip ahead
13+
if (nextStep.getTime() <= now) {
14+
// Calculate a second step to determine the interval
15+
const secondStep = calculateNextStep(schedule, timezone, nextStep);
16+
const interval = secondStep.getTime() - nextStep.getTime();
17+
18+
// If we have a consistent interval and it would take many iterations,
19+
// skip ahead mathematically instead of iterating
20+
if (interval > 0) {
21+
const stepsNeeded = Math.floor((now - nextStep.getTime()) / interval);
22+
23+
// Only skip ahead if it would save us more than a few iterations
24+
if (stepsNeeded > 10) {
25+
// Skip ahead by calculating how many intervals to add
26+
const skipAheadTime = nextStep.getTime() + stepsNeeded * interval;
27+
nextStep = calculateNextStep(schedule, timezone, new Date(skipAheadTime));
28+
}
29+
}
30+
31+
// Use the normal iteration for the remaining steps (should be <= 10 now)
32+
while (nextStep.getTime() <= now) {
33+
nextStep = calculateNextStep(schedule, timezone, nextStep);
34+
}
1235
}
1336

1437
return nextStep;

0 commit comments

Comments
 (0)