@@ -337,8 +337,27 @@ export async function remove(state: CronServiceState, id: string) {
337337 } ) ;
338338}
339339
340- export async function run ( state : CronServiceState , id : string , mode ?: "due" | "force" ) {
341- const prepared = await locked ( state , async ( ) => {
340+ type PreparedManualRun =
341+ | {
342+ ok : true ;
343+ ran : false ;
344+ reason : "already-running" | "not-due" ;
345+ }
346+ | {
347+ ok : true ;
348+ ran : true ;
349+ jobId : string ;
350+ startedAt : number ;
351+ executionJob : CronJob ;
352+ }
353+ | { ok : false } ;
354+
355+ async function prepareManualRun (
356+ state : CronServiceState ,
357+ id : string ,
358+ mode ?: "due" | "force" ,
359+ ) : Promise < PreparedManualRun > {
360+ return await locked ( state , async ( ) => {
342361 warnIfDisabled ( state , "run" ) ;
343362 await ensureLoaded ( state , { skipRecompute : true } ) ;
344363 // Normalize job tick state (clears stale runningAtMs markers) before
@@ -363,7 +382,7 @@ export async function run(state: CronServiceState, id: string, mode?: "due" | "f
363382 // force-reload from disk cannot start the same job concurrently.
364383 await persist ( state ) ;
365384 emit ( state , { jobId : job . id , action : "started" , runAtMs : now } ) ;
366- const executionJob = JSON . parse ( JSON . stringify ( job ) ) as typeof job ;
385+ const executionJob = JSON . parse ( JSON . stringify ( job ) ) as CronJob ;
367386 return {
368387 ok : true ,
369388 ran : true ,
@@ -372,13 +391,13 @@ export async function run(state: CronServiceState, id: string, mode?: "due" | "f
372391 executionJob,
373392 } as const ;
374393 } ) ;
394+ }
375395
376- if ( ! prepared . ran ) {
377- return prepared ;
378- }
379- if ( ! prepared . executionJob || typeof prepared . startedAt !== "number" ) {
380- return { ok : false } as const ;
381- }
396+ async function finishPreparedManualRun (
397+ state : CronServiceState ,
398+ prepared : Extract < PreparedManualRun , { ran : true } > ,
399+ mode ?: "due" | "force" ,
400+ ) : Promise < void > {
382401 const executionJob = prepared . executionJob ;
383402 const startedAt = prepared . startedAt ;
384403 const jobId = prepared . jobId ;
@@ -459,7 +478,28 @@ export async function run(state: CronServiceState, id: string, mode?: "due" | "f
459478 await persist ( state ) ;
460479 armTimer ( state ) ;
461480 } ) ;
481+ }
462482
483+ export async function run ( state : CronServiceState , id : string , mode ?: "due" | "force" ) {
484+ const prepared = await prepareManualRun ( state , id , mode ) ;
485+ if ( ! prepared . ran ) {
486+ return prepared ;
487+ }
488+ await finishPreparedManualRun ( state , prepared , mode ) ;
489+ return { ok : true , ran : true } as const ;
490+ }
491+
492+ export async function enqueueRun ( state : CronServiceState , id : string , mode ?: "due" | "force" ) {
493+ const prepared = await prepareManualRun ( state , id , mode ) ;
494+ if ( ! prepared . ran ) {
495+ return prepared ;
496+ }
497+ void finishPreparedManualRun ( state , prepared , mode ) . catch ( ( err ) => {
498+ state . deps . log . error (
499+ { jobId : prepared . jobId , err : String ( err ) } ,
500+ "cron: queued manual run background execution failed" ,
501+ ) ;
502+ } ) ;
463503 return { ok : true , ran : true } as const ;
464504}
465505
0 commit comments