3. Scheduled Task Options Today
● Adobe Scheduled Tasks
(Uses Quartz engine)
● Lucee Scheduled Tasks
(Uses custom scheduler thread)
● Cron jobs/Jenkins jobs that hit URL
Completely external to the JVM
4. Scheduled Task Pain Points
● Limited scheduling capabilities
● LImited error handling
● Hard to cluster
● Each CF engine has different config
● External scheduling isn’t portable
● Can ‘t contribute run-time additions to scheduled tasks
● Usually based around public facing CFMs
● Not OO, not functional
5. What does the JDK Offer?
● The java.util.concurrent package!
● “Utility classes commonly useful in concurrent programming…
includes a few small standardized extensible frameworks… that
provide useful functionality and are otherwise tedious or difficult
to implement. “
● TimeUnit class for tracking seconds, minutes, hours, etc
● ThreadPoolExecutor and ScheduledThreadPoolExecutor
provide tunable, flexible thread pools.
6. ColdBox Scheduled Tasks
● NOT ACTUALLY COLDBOX SPECIFIC!! Also available in standalone
WireBox, LogBox, and CacheBox via the AsyncManager
● Define robust schedules via fluent DSL
● Uses Configuration as Code so no CF engine config and all contained in the
app
● Runs the same on all CF engines
● No external scheduling mechanism
● Built-in lifecycle methods and exception handling
● Built in clustering support to only run some tasks on one server
● Composable module-specific schedulers for drop-in HMVC functionality
10. ColdBox Scheduler Convention
● Located in /config/Scheduler.cfc
● Our app templates are already updated to include it
● Works similar to Router.cfc-- automatic inheritance and
fluent DSL to call to configure the scheduler
15. Scheduler Life-Cycle Methods
● onStartup() - Called after the scheduler has registered all schedules
● onShutdown() - Called before the scheduler is going to be shutdown
● onAnyTaskError(task,exception) - Called whenever ANY task fails
● onAnyTaskSuccess(task,result) - Called whenever ANY task succeeds
● beforeAnyTask(task) - Called before ANY task runs
● afterAnyTask(task,result) - Called after ANY task runs
16. Scheduler Life-Cycle Methods
component {
function configure() {
// Tasks here
}
function onStartup(){
log.info( 'Scheduler ready to rock and roll!' );
}
function onAnyTaskError( required task, required e ){
log.error( 'Task #task.getName()# has bombed!', e );
}
}
/config/Scheduler.cfc
18. Scheduler Configuration Methods
● setCacheName( cacheName ) - Set the cachename to use for all
registered tasks
● setServerFixation( boolean ) - Set the server fixation to use for all
registered tasks
● setTimezone( timezone ) - Set the timezone to use for all registered tasks
● setExecutor( executor ) - Override the executor generated for the
scheduler
30. Scheduler everyXXX() methods
.onWeekends( time )
.onWeekdays( time )
.onMondays( time )
.onTuesdays( time )
.onWednesdays( time )
.onThursdays( time )
.onFridays( time )
.onSaturdays( time )
.onSundays( time )
31. Scheduler one-off tasks
component {
function configure() {
// Warm up caches 1 minute after app comes online
task( "build-up-cache" )
.call( () => getInstance( "DataServices" ).buildCache() )
.delay( 1, "minutes" );
}
}
/config/Scheduler.cfc
33. Task Life-Cycle Methods
● after( target ) - Store the closure to execute after the task executes
● before( target ) - Store the closure to execute before the task executes
● onFailure( target ) - Store the closure to execute if there is a failure running
the task
● onSuccess( target ) - Store the closure to execute if the task completes
successfully
40. Task Stats
● created - The timestamp of when the task was created in memory
● lastRun - The last time the task ran
● nextRun - When the task will run next
● totalFailures - How many times the task has failed execution
● totalRuns - How many times the task has run
● totalSuccess - How many times the task has run and succeeded
43. Schedulers For Modules
● Every module can have its own scheduler!
● Injectable as cbScheduler@{moduleName}
● Lifecycle is tied to module load/unload
● Provides portable, drop in tasks
44. Schedulers For Modules - Example
task( "unleashsdk-refresh-features" )
.call( getInstance( "UnleashSDK@unleashsdk" ), "refreshFeatures" )
.every( variables.refreshInterval, "seconds" )
.before( function() {
if ( log.canDebug() ) {
log.debug( "Starting to fetch new features from Unleash" );
}
} )
.onSuccess( function( task, results ) {
if ( log.canInfo() ) {
log.info( "Successfully refreshed features", results );
}
} )
.onFailure( function( task, exception ) {
if ( log.canError() ) {
log.error( "Exception when running task [unleashsdk-refresh-features]:", exception );
}
} );
https://github.com/coldbox-modules/unleashsdk/blob/main/config/Scheduler.cfc
45. The End (Q & A)
https://coldbox.ortusbooks.com/digging-deeper/scheduled-tasks
Brad Wood
@bdw429s
brad@bradwood.com