Coldbox and VueJS untangled

Scheduled tasks in Coldbox

I often post about problematic stuff, like bugs, incomplete documentation or other annoyances. This post is different, and not even very detailed. We are talking about scheduling tasks. Luis Majano recently described the coldbox 6.4.0 release, which is mainly about scheduling. There is extensive documentation but scheduling is now so easy to code, I just wanted to share some examples with you. Coldbox 6.4 was only released a few weeks ago, but I think is is so extremely useful, we already implemented it in several projects. Ok, there was one bug which I will share with you, but that will be fixed soon, and is easy to avoid.

So why am I so happy about scheduling in ColdBox? Ok, disclaimer first:

Scheduled Tasks are NOT a ColdBox only feature. They are available in all of our STANDALONE libraries: CacheBox, LogBox and WireBox. THEY CAN BE USED IN ANY ANY, I REPEAT ANY, COLDFUSION (CFML) APPLICATION THAT IS NOT, NOT, NOT COLDBOX.

https://www.ortussolutions.com/blog/coldbox-640-released-welcome-to-the-land-of-scheduled-tasks

So although I am using it in Coldbox, you can use it in any CFML application. Scheduled task have always been complicated in CFML (and in many other languages). Are you scheduling from within Lucee or ACF with <cfschedule> or from a cron or windows task scheduler? We did it all.

  • We didn’t like cfschedule, because it was not always reliable.
  • It is easy to forget your cron schedule or windows task scheduler when moving applications to other machines.
  • Most of the methods were not very granular, so a scheduled task with a 1 minute frequency could be accomplished, but if you need something with a higher frequency you have to do some tricks.

What I didn’t like especially about the ‘old school’ scheduling: security. With the mentioned tools you have to initiate your process from some webpage. If this is a process which changes things, or uses a lot of resources, you don’t want to open your scheduling pages to the public. We built a few systems which are fully secured, so we had to create special authentication method for these pages, which were quite different from our regular authentication and authorization schemes. It would be a lot easier if I could call my tasks from within my application, so I don’t have to worry about external access.

Thats exactly what you can do with the new scheduled tasks in Coldbox. In the Coldbox config directory you can create a Scheduler.cfc which will be read at startup. This scheduler has many methods, I’ll summarize them here

methodpurpose
configurethis is were you define your tasks, set frequencies, scheduling times and all kind of limits (which server, which environment etc)
onStartupfires when the scheduler starts.
onShutdownfires when the scheduler stops.
onAnyTaskErrorif you want to keep track of your errors you can use this method to log any errors, send alerts or anything else you can think of
onAnyTaskSuccessYou can register when a tasks finished successfully. If your scheduled task returns something, the result is available in this method. So again, you can mail the result, page someone or anything you like.
beforeAnyTask
afterAnyTask

We use the afterAnyTask and onStartup for logging. We created a special scheduler logger so we can see what’s going on:

component {

  property name="schedulerLogger"        inject="logbox:logger:scheduledTasks" ;
  /**
   * Called after the scheduler has registered all schedules
  */
  function onStartup(){
    schedulerLogger.info("Scheduler started");
  }
  /**
   * Called after ANY task runs
   *
   * @task The task that got executed
   * @result The result (if any) that the task produced
   */
  function afterAnyTask( required task, result ){
    schedulerLogger.info( "task #task.getName()# just ran.", task.getStats() );
  }

In our case we just had to make sure our named logger (logbox:logger:scheduledTasks) existed, or your log request will end up in the default logger. As you can see from our afterAnyTask method, you can log all your task statistics(), or write them to a database. We are still investigating a few things, but this way we could build some nice dashboard which reads the stats for our tasks.

But now for the most important part. How do we configure our scheduled tasks? Our Scheduler has a configure method. This is the first task we configured:

function configure() {

  task( "Send daily promotion statistics" )
    .call( 
      () => getInstance( "ReportService" ).mailActivePromotionsStatistics() 
    )
    .everyDayAt( "08:00" );
}

Well, it doesn’t get easier than that. Just create some method in a service which performs a task, and register it in Scheduler.cfc. This task is scheduled every day at 8am, but we can also schedule tasks every minute or even every millisecond.

task( "Check stock Levels" )
  .call( 
    () => getInstance( "ReportService" ).mailCurrentStockWarning() 
  )
  .every( 1, "minutes" )

There are many methods available both for scheduling at fixed times and for scheduling at fixed intervals. The coldbox documentation has many more examples. Let me show you my last example:

task( "Check stock Levels" )
  .call( 
    () => getInstance( "ReportService" ).mailCurrentStockWarning() 
  )
  .every( 1, "minutes" )
  .when( function() {
    return  ( hour(now()) >= 8 and hour(now() < 21 ));
  })
  .onEnvironment( [ "staging", "production" ] )
  .onOneServer();

In this example I am limiting the execution: if we loadbalance our app we can limit the exution to one server (with onOneServer() ). I can also limit the environment, and the most flexible one: when( function(){} ). The when function accept a closure and if this closure returns false the execution of our task will be skipped. This way I added some additional time conditions( every 1 minute, but only between 9am and pm). The possibilities are endless.

The scheduler is very powerful. You can announce interceptors, read or change settings, render views and much more. A few examples were we are using it for already

  • read virtual machine info from our hosting environment
  • calculate server uptimes and generate SLA reports
  • import registered domains and compare with invoicing
  • send daily mailing statistics to our sales team
  • monitoring all kind of alert levels and send warnings when required
  • synchronize files with some of our suppliers

And all of this without any crontab or external security requirements. I really love this stuff, it is one of the best new features in Coldbox. Or any CFML site I should say.

A few more important things: any module can use it’s own Scheduler.cfc. Last but not least: you don’t have to use Coldbox to use the scheduled task. The same features are available from CacheBox, Logbox and Wirebox.

Ok, I promised I would share one bug with you. For now please don’t use lambda expressions in your .when() function. The reason is explained in this post, but let’s not spoil the joy of scheduling: Luis Majano promised me this small issue will be fixed soon!

2 Comments

  1. Daemach Laratin

    In coldbox, the app is not initialized until something triggers it – usually by loading a web page. This situation will prevent the scheduler from initializing too. What’s the best way of ensuring that everything is initialized on startup without relying on an external source?

    • Wil

      I think you are right. This might be relevant if you have some very time sensitive scheduled tasks, and there is probably no real solution if you exclude external sources.
      In our scenario we are monitoring all servers with an external monitoring program which hits the server every minute. In some situations we have loadbalancers which hit a cf url every 4 seconds. And if you have some traffic on your site most of the times you don’t have to wait too long. So for us it is no real world problem.
      But if you want to be sure the scheduler is started, you should hit the site directly after the start. So instead of just starting the service you could create a startup proces which starts the service, and continues by hitting an URL which will start the scheduler.
      But I think any relevant site should be monitored externally in some way, and if the frequency is high enough, that will solve the problem.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

© 2021 ShiftInsert.nl

Theme by Anders NorenUp ↑