Skip to content

Commit d78ed00

Browse files
committed
fix upcoming timestamps
1 parent 466cfcd commit d78ed00

2 files changed

Lines changed: 53 additions & 19 deletions

File tree

internal-packages/schedule-engine/src/engine/index.ts

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -174,18 +174,7 @@ export class ScheduleEngine {
174174
instance.taskSchedule.generatorExpression
175175
);
176176

177-
const scheduleWindow: NormalizedScheduleWindow | undefined =
178-
instance.taskSchedule.windowPercentage !== null
179-
? {
180-
type: "percentage",
181-
percentage: instance.taskSchedule.windowPercentage,
182-
}
183-
: instance.taskSchedule.windowDurationSeconds !== null
184-
? {
185-
type: "duration",
186-
durationSeconds: instance.taskSchedule.windowDurationSeconds,
187-
}
188-
: undefined;
177+
const scheduleWindow = normalizedScheduleWindow(instance.taskSchedule);
189178
const schedulePhase =
190179
instance.schedulePhase ??
191180
calculateSchedulePhase({
@@ -528,6 +517,33 @@ export class ScheduleEngine {
528517
// 3. undefined — first-ever fire (no previous fire to point at).
529518
const lastTimestamp =
530519
params.lastScheduleTime ?? instance.lastScheduledTimestamp ?? undefined;
520+
const actualExecutionTime = new Date();
521+
const scheduleWindow = normalizedScheduleWindow(instance.taskSchedule);
522+
const schedulePhase =
523+
instance.schedulePhase ??
524+
calculateSchedulePhase({
525+
secret: this.options.schedulePhaseSecret,
526+
environmentId: instance.environmentId,
527+
deduplicationKey: instance.taskSchedule.deduplicationKey,
528+
});
529+
const nextOccurrence = calculateNextSchedulableOccurrence({
530+
schedule: instance.taskSchedule.generatorExpression,
531+
timezone: instance.taskSchedule.timezone,
532+
afterNominal: exactScheduleTime,
533+
now: actualExecutionTime,
534+
schedulePhase,
535+
window: scheduleWindow,
536+
cronSpreadEnabled: this.options.cronSpreadEnabled,
537+
});
538+
const upcoming = [
539+
nextOccurrence.nominalAt,
540+
...nextScheduledTimestamps(
541+
instance.taskSchedule.generatorExpression,
542+
instance.taskSchedule.timezone,
543+
nextOccurrence.nominalAt,
544+
9
545+
),
546+
];
531547

532548
const payload = {
533549
scheduleId: instance.taskSchedule.friendlyId,
@@ -536,16 +552,10 @@ export class ScheduleEngine {
536552
lastTimestamp,
537553
externalId: instance.taskSchedule.externalId ?? undefined,
538554
timezone: instance.taskSchedule.timezone,
539-
upcoming: nextScheduledTimestamps(
540-
instance.taskSchedule.generatorExpression,
541-
instance.taskSchedule.timezone,
542-
exactScheduleTime,
543-
10
544-
),
555+
upcoming,
545556
};
546557

547558
// Calculate execution timing metrics
548-
const actualExecutionTime = new Date();
549559
const schedulingAccuracyMs = actualExecutionTime.getTime() - exactScheduleTime.getTime();
550560

551561
span.setAttribute("scheduling_accuracy_ms", schedulingAccuracyMs);
@@ -993,3 +1003,21 @@ export class ScheduleEngine {
9931003
}
9941004
}
9951005
}
1006+
1007+
function normalizedScheduleWindow({
1008+
windowDurationSeconds,
1009+
windowPercentage,
1010+
}: {
1011+
windowDurationSeconds: number | null;
1012+
windowPercentage: number | null;
1013+
}): NormalizedScheduleWindow | undefined {
1014+
if (windowPercentage !== null) {
1015+
return { type: "percentage", percentage: windowPercentage };
1016+
}
1017+
1018+
if (windowDurationSeconds !== null) {
1019+
return { type: "duration", durationSeconds: windowDurationSeconds };
1020+
}
1021+
1022+
return undefined;
1023+
}

internal-packages/schedule-engine/test/scheduleEngine2.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,12 @@ describe("ScheduleEngine Integration (part 2)", () => {
115115
// Falls back to instance.lastScheduledTimestamp from the DB rather
116116
// than reporting undefined for this one transitional fire.
117117
expect(triggerCalls[0].payload.lastTimestamp).toEqual(preDeployLastFire);
118+
expect(triggerCalls[0].payload.upcoming).toHaveLength(10);
119+
expect(
120+
triggerCalls[0].payload.upcoming.every(
121+
(timestamp) => timestamp.getTime() > beforeTrigger.getTime()
122+
)
123+
).toBe(true);
118124

119125
const nextJob = await engine.getJob(`scheduled-task-instance:${scheduleInstance.id}`);
120126
const nextJobPayload = nextJob!.item as unknown as {

0 commit comments

Comments
 (0)