@@ -4,11 +4,16 @@ import {
44 ReloadEvent ,
55 logResponse ,
66} from "@miniflare/core" ;
7- import type { ScheduledTask } from "node- cron" ;
7+ import type { Cron , ITimerHandle } from "cron-schedule " ;
88import { SchedulerPlugin } from "./plugin" ;
99
1010export * from "./plugin" ;
1111
12+ export interface CronScheduler {
13+ setInterval ( cron : Cron , task : ( ) => any ) : ITimerHandle ;
14+ clearTimeoutOrInterval ( handle : ITimerHandle ) : void ;
15+ }
16+
1217export type SchedulerPluginSignatures = CorePluginSignatures & {
1318 SchedulerPlugin : typeof SchedulerPlugin ;
1419} ;
@@ -17,56 +22,63 @@ const kReload = Symbol("kReload");
1722
1823export class Scheduler < Plugins extends SchedulerPluginSignatures > {
1924 // noinspection JSMismatchedCollectionQueryUpdate
20- private previousValidatedCrons ?: string [ ] ;
21- private scheduledTasks ?: ScheduledTask [ ] ;
25+ private previousValidatedCrons ?: Cron [ ] ;
26+ private scheduledHandles ?: ITimerHandle [ ] ;
2227
2328 constructor (
2429 private readonly mf : MiniflareCore < Plugins > ,
25- private readonly cron : Promise < {
26- default : typeof import ( "node- cron" ) ;
27- } > = import ( "node-cron" )
30+ private readonly cronScheduler : Promise < CronScheduler > = import (
31+ " cron-schedule"
32+ ) . then ( ( module ) => module . TimerBasedCronScheduler )
2833 ) {
29- this [ kReload ] = this [ kReload ] . bind ( this ) ;
3034 mf . addEventListener ( "reload" , this [ kReload ] ) ;
3135 }
3236
33- async [ kReload ] ( event : ReloadEvent < Plugins > ) : Promise < void > {
37+ [ kReload ] = async ( event : ReloadEvent < Plugins > ) : Promise < void > = > {
3438 const validatedCrons = event . plugins . SchedulerPlugin . validatedCrons ;
3539 // Checking references here, if different, SchedulerPlugin setup must've
3640 // been called meaning crons changed so reload scheduled tasks
3741 if ( this . previousValidatedCrons === validatedCrons ) return ;
3842 this . previousValidatedCrons = validatedCrons ;
3943
44+ const cronScheduler = await this . cronScheduler ;
45+
4046 // Schedule tasks, stopping all current ones first
41- this . scheduledTasks ?. forEach ( ( task ) => task . destroy ( ) ) ;
47+ this . scheduledHandles ?. forEach ( ( handle ) =>
48+ cronScheduler . clearTimeoutOrInterval ( handle )
49+ ) ;
4250 if ( ! validatedCrons . length ) return ;
43- const cron = await this . cron ;
44- this . scheduledTasks = validatedCrons ?. map ( ( expression ) =>
45- cron . default . schedule ( expression , async ( ) => {
51+
52+ this . scheduledHandles = validatedCrons ?. map ( ( cron ) => {
53+ const spec = cron . toString ( ) ;
54+ return cronScheduler . setInterval ( cron , async ( ) => {
4655 const start = process . hrtime ( ) ;
4756 // scheduledTime will default to Date.now()
48- const waitUntil = this . mf . dispatchScheduled ( undefined , expression ) ;
57+ const waitUntil = this . mf . dispatchScheduled ( undefined , spec ) ;
4958 await logResponse ( this . mf . log , {
5059 start,
5160 method : "SCHD" ,
52- url : expression ,
61+ url : spec ,
5362 waitUntil,
5463 } ) ;
55- } )
56- ) ;
57- }
64+ } ) ;
65+ } ) ;
66+ } ;
5867
59- dispose ( ) : void {
68+ async dispose ( ) : Promise < void > {
6069 this . mf . removeEventListener ( "reload" , this [ kReload ] ) ;
61- this . scheduledTasks ?. forEach ( ( task ) => task . destroy ( ) ) ;
70+ const cronScheduler = await this . cronScheduler ;
71+ this . scheduledHandles ?. forEach ( ( handle ) =>
72+ cronScheduler . clearTimeoutOrInterval ( handle )
73+ ) ;
6274 }
6375}
6476
6577export async function startScheduler < Plugins extends SchedulerPluginSignatures > (
6678 mf : MiniflareCore < Plugins > ,
67- cron ?: Promise < { default : typeof import ( "node-cron" ) } >
79+ cronScheduler ?: Promise < CronScheduler >
6880) : Promise < Scheduler < Plugins > > {
69- const scheduler = new Scheduler ( mf , cron ) ;
81+ const scheduler = new Scheduler ( mf , cronScheduler ) ;
7082 await scheduler [ kReload ] ( new ReloadEvent ( await mf . getPlugins ( ) ) ) ;
7183 return scheduler ;
7284}
0 commit comments