From 69814c268414a71891309350764128731767febb Mon Sep 17 00:00:00 2001 From: Eric Peterson Date: Tue, 30 Jan 2024 17:03:15 -0700 Subject: [PATCH] Restart the scheduler to call configure again to get new tasks --- system/async/tasks/Scheduler.cfc | 35 ++++++++++++++++++++---- system/web/services/SchedulerService.cfc | 17 +++++++++++- 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/system/async/tasks/Scheduler.cfc b/system/async/tasks/Scheduler.cfc index 5c2eec07d..8cf2c1169 100644 --- a/system/async/tasks/Scheduler.cfc +++ b/system/async/tasks/Scheduler.cfc @@ -63,13 +63,8 @@ component accessors="true" singleton { variables.tasks = structNew( "ordered" ); // Default TimeZone to UTC for all tasks variables.timezone = createObject( "java", "java.time.ZoneId" ).systemDefault(); - // Build out the executor for this scheduler - variables.executor = arguments.asyncManager.newExecutor( - name: arguments.name & "-scheduler", - type: "scheduled" - ); // Bit that denotes if this scheduler has been started or not - variables.started = false; + variables.started = false; // Send notice arguments.asyncManager.out( "√ Scheduler (#arguments.name#) has been registered" ); @@ -167,6 +162,12 @@ component accessors="true" singleton { if ( !variables.started ) { lock name="scheduler-#getName()#-startup" type="exclusive" timeout="45" throwOnTimeout="true" { if ( !variables.started ) { + // Build out the executor for this scheduler + variables.executor = arguments.asyncManager.newExecutor( + name: arguments.name & "-scheduler", + type: "scheduled" + ); + // Iterate over tasks and send them off for scheduling variables.tasks.each( function( taskName, taskRecord ){ // Verify we can start it up the task or not @@ -250,6 +251,28 @@ component accessors="true" singleton { return this; } + /** + * Restarts a scheduler by shutting it down, clearing out the tasks, calling `configure`, and starting it again. + * Useful when loading tasks from a database or other dynamic sources. + * + * @force If true, it forces all shutdowns this is usually true when doing reinits + * @timeout The timeout in seconds to wait for the shutdown of all tasks, defaults to 30 or whatever you set using the setShutdownTimeout() method + */ + public Scheduler function restart( boolean force = false, numeric timeout = variables.shutdownTimeout ){ + variables.asyncManager.out( "√ Scheduler (#arguments.name#) is being restarted" ); + shutdown( argumentCollection = arguments ); + clearTasks(); + configure(); + startup(); + variables.asyncManager.out( "√ Scheduler (#arguments.name#) has been restarted" ); + return this; + } + + public Scheduler function clearTasks(){ + variables.tasks = structNew( "ordered" ); + return this; + } + /** * -------------------------------------------------------------------------- * Life - Cycle Callbacks diff --git a/system/web/services/SchedulerService.cfc b/system/web/services/SchedulerService.cfc index 1eb3856b0..205b7eee4 100644 --- a/system/web/services/SchedulerService.cfc +++ b/system/web/services/SchedulerService.cfc @@ -146,7 +146,7 @@ component extends="coldbox.system.web.services.BaseService" accessors="true" { } /** - * This method is ran by the laoder service once the ColdBox application is ready to serve requests. + * This method is ran by the loader service once the ColdBox application is ready to serve requests. * It will startup all the schedulers in the order they where registered. */ SchedulerService function startupSchedulers(){ @@ -195,4 +195,19 @@ component extends="coldbox.system.web.services.BaseService" accessors="true" { return false; } + /** + * Restarts a scheduler from this manager, if it exists. + * + * @name The name of the scheduler + * + * @return True if restarted, false if not found + */ + boolean function restartScheduler( required name ){ + if ( hasScheduler( arguments.name ) ) { + variables.schedulers[ arguments.name ].restart(); + return true; + } + return false; + } + }