@@ -6,6 +6,7 @@ import { authenticateApiKeyWithScope } from "~/services/apiAuth.server";
66import { logger } from "~/services/logger.server" ;
77import { env } from "~/env.server" ;
88import { calculateNextScheduleRunTimes , normalizeScheduleWindow } from "~/v3/scheduleWindow.server" ;
9+ import { nextScheduledTimestamps } from "~/v3/utils/calculateNextSchedule.server" ;
910
1011const ParamsSchema = z . object ( {
1112 deploymentId : z . string ( ) ,
@@ -58,39 +59,75 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
5859 const workerMetadata = deployment . worker
5960 ? BackgroundWorkerMetadata . safeParse ( deployment . worker . metadata )
6061 : undefined ;
61- const declarativeSchedules = workerMetadata ?. success
62+ const declarativeTasks = workerMetadata ?. success
6263 ? workerMetadata . data . tasks . flatMap ( ( task ) => {
64+ const schedule = task . schedule ;
6365 if (
64- ! task . schedule ||
65- ( task . schedule . environments &&
66- ! task . schedule . environments . includes ( authenticatedEnv . type ) )
66+ ! schedule ||
67+ ( schedule . environments && ! schedule . environments . includes ( authenticatedEnv . type ) )
6768 ) {
6869 return [ ] ;
6970 }
7071
71- const windowFields = normalizeScheduleWindow ( task . schedule . window ) ;
72- const [ nextRun ] = calculateNextScheduleRunTimes ( {
72+ return [ { id : task . id , schedule } ] ;
73+ } )
74+ : [ ] ;
75+ const persistedDeclarativeSchedules =
76+ declarativeTasks . length > 0
77+ ? await prisma . taskSchedule . findMany ( {
78+ where : {
79+ type : "DECLARATIVE" ,
80+ projectId : authenticatedEnv . projectId ,
81+ taskIdentifier : { in : declarativeTasks . map ( ( task ) => task . id ) } ,
82+ instances : { some : { environmentId : authenticatedEnv . id } } ,
83+ } ,
84+ select : {
85+ taskIdentifier : true ,
86+ deduplicationKey : true ,
87+ generatorExpression : true ,
88+ timezone : true ,
89+ windowDurationSeconds : true ,
90+ windowPercentage : true ,
91+ instances : {
92+ where : { environmentId : authenticatedEnv . id } ,
93+ select : { schedulePhase : true } ,
94+ } ,
95+ } ,
96+ } )
97+ : [ ] ;
98+ const declarativeSchedules = declarativeTasks . map ( ( task ) => {
99+ const windowFields = normalizeScheduleWindow ( task . schedule . window ) ;
100+ const persistedSchedule = persistedDeclarativeSchedules . find (
101+ ( schedule ) =>
102+ schedule . taskIdentifier === task . id &&
103+ schedule . generatorExpression === task . schedule . cron &&
104+ schedule . timezone === task . schedule . timezone &&
105+ schedule . windowDurationSeconds === windowFields . windowDurationSeconds &&
106+ schedule . windowPercentage === windowFields . windowPercentage
107+ ) ;
108+ const registeredNextRun = persistedSchedule
109+ ? calculateNextScheduleRunTimes ( {
73110 cron : task . schedule . cron ,
74111 timezone : task . schedule . timezone ,
75- deduplicationKey : task . id ,
112+ deduplicationKey : persistedSchedule . deduplicationKey ,
76113 environmentId : authenticatedEnv . id ,
77- schedulePhase : null ,
114+ schedulePhase : persistedSchedule . instances [ 0 ] ?. schedulePhase ?? null ,
78115 phaseSecret : env . ENCRYPTION_KEY ,
79116 ...windowFields ,
80- } ) ;
117+ } ) [ 0 ]
118+ : undefined ;
81119
82- return [
83- {
84- task : task . id ,
85- cron : task . schedule . cron ,
86- timezone : task . schedule . timezone ,
87- window : task . schedule . window ,
88- nextRun : nextRun . nominalAt ,
89- nextRunEffectiveAt : nextRun . effectiveAt ,
90- } ,
91- ] ;
92- } )
93- : [ ] ;
120+ return {
121+ task : task . id ,
122+ cron : task . schedule . cron ,
123+ timezone : task . schedule . timezone ,
124+ window : task . schedule . window ,
125+ nextRun :
126+ registeredNextRun ?. nominalAt ??
127+ nextScheduledTimestamps ( task . schedule . cron , task . schedule . timezone , new Date ( ) ) [ 0 ] ,
128+ nextRunEffectiveAt : registeredNextRun ?. effectiveAt ?? null ,
129+ } ;
130+ } ) ;
94131
95132 return json ( {
96133 id : deployment . friendlyId ,
0 commit comments