import { setImmediate } from "timers/promises" ; import { BindingsPlugin , ScheduledEvent } from "@miniflare/core" ; import { CronScheduler , CronSchedulerImpl , SchedulerPlugin , startScheduler , } from "@miniflare/scheduler" ; import { Awaitable } from "@miniflare/shared" ; import { TestLog , useMiniflare } from "@miniflare/shared-test" ; import test from "ava" ; import { Cron , ITimerHandle } from "cron-schedule" ; function createCronScheduler ( ) { const crons = new Map < string , Set < ( ) => Awaitable < void > > > ( ) ; const scheduler = { setInterval ( cron , task ) { const spec = cron . toString ( ) ; const set = crons . get ( spec ) ?? new Set ( ) ; crons . set ( spec , set ) ; set . add ( task ) ; return [ spec , task ] as any ; } , clearTimeoutOrInterval ( [ spec , task ] ) { crons . get ( spec ) ?. delete ( task ) ; } , } ; const dispatch = async ( cron ) => { await Promise . all ( Array . from ( crons . get ( cron ) ?? [ ] ) . map ( ( func ) => func ( ) ) ) ; } ; return [ dispatch , Promise . resolve ( scheduler ) ] ; } test ( "CronScheduler: schedules tasks for validated CRONs on reload" , async ( t ) => { let events = [ ] ; const log = new TestLog ( ) ; const mf = useMiniflare ( { SchedulerPlugin , BindingsPlugin } , { globals : { eventCallback : ( event ) => events . push ( event ) } , script : 'addEventListener("scheduled", eventCallback)' , crons : [ "15 * * * *" , "30 * * * *" ] , } , log ) ; await mf . getPlugins ( ) ; const [ dispatch , cronScheduler ] = createCronScheduler ( ) ; new CronScheduler ( mf , cronScheduler ) ; await setImmediate ( ) ; await dispatch ( "15 * * * *" ) ; t . deepEqual ( events , [ ] ) ; await mf . reload ( ) ; log . logs = [ ] ; await dispatch ( "15 * * * *" ) ; t . is ( events . length , 1 ) ; t . is ( events [ 0 ] . cron , "15 * * * *" ) ; t . regex ( log . logs [ 0 ] [ 1 ] , /^SCHD 15 \* \* \* \* \(\d+\.\d+ms\)$/ ) ; events = [ ] ; log . logs = [ ] ; await dispatch ( "30 * * * *" ) ; t . is ( events . length , 1 ) ; t . is ( events [ 0 ] . cron , "30 * * * *" ) ; t . regex ( log . logs [ 0 ] [ 1 ] , /^SCHD 30 \* \* \* \* \(\d+\.\d+ms\)$/ ) ; } ) ; test ( "CronScheduler: destroys tasks when CRONs change" , async ( t ) => { const events = [ ] ; const options = { globals : { eventCallback : ( event ) => events . push ( event ) } , script : 'addEventListener("scheduled", eventCallback)' , crons : [ "15 * * * *" ] , } ; const mf = useMiniflare ( { SchedulerPlugin , BindingsPlugin } , options ) ; await mf . getPlugins ( ) ; const [ dispatch , cronScheduler ] = createCronScheduler ( ) ; new CronScheduler ( mf , cronScheduler ) ; await mf . reload ( ) ; t . is ( events . length , 0 ) ; await dispatch ( "15 * * * *" ) ; t . is ( events . length , 1 ) ; await mf . setOptions ( { ... options , crons : [ "30 * * * *" ] } ) ; await dispatch ( "15 * * * *" ) ; t . is ( events . length , 1 ) ; await dispatch ( "30 * * * *" ) ; t . is ( events . length , 2 ) ; } ) ; test ( "CronScheduler: dispose: destroys tasks and removes reload listener" , async ( t ) => { const events = [ ] ; const mf = useMiniflare ( { SchedulerPlugin , BindingsPlugin } , { globals : { eventCallback : ( event ) => events . push ( event ) } , script : 'addEventListener("scheduled", eventCallback)' , crons : [ "15 * * * *" ] , } ) ; await mf . getPlugins ( ) ; const [ dispatch , cronScheduler ] = createCronScheduler ( ) ; const scheduler = new CronScheduler ( mf , cronScheduler ) ; await mf . reload ( ) ; t . is ( events . length , 0 ) ; await dispatch ( "15 * * * *" ) ; t . is ( events . length , 1 ) ; await scheduler . dispose ( ) ; await dispatch ( "15 * * * *" ) ; t . is ( events . length , 1 ) ; } ) ; test ( "createScheduler: automatically schedules tasks" , async ( t ) => { const events = [ ] ; const mf = useMiniflare ( { SchedulerPlugin , BindingsPlugin } , { globals : { eventCallback : ( event ) => events . push ( event ) } , script : 'addEventListener("scheduled", eventCallback)' , crons : [ "15 * * * *" ] , } ) ; await mf . getPlugins ( ) ; const [ dispatch , cronScheduler ] = createCronScheduler ( ) ; await startScheduler ( mf , cronScheduler ) ; t . is ( events . length , 0 ) ; await dispatch ( "15 * * * *" ) ; t . is ( events . length , 1 ) ; } ) ;