TorqueBox has had support for scheduled jobs since the beginning of the project.
Scheduled jobs can be very helpful when you want to do something not
necessarily now but at some point in the future. If you are familiar with cron
expressions you even already
know how to define the job trigger expression. If you don't - don't worry - it's easy
to understand. Jobs are implemented as plain Ruby
classes that are only
required to implement a
run method. That's all.
TorqueBox takes care of firing the job at the correct time.
Simple and still cool.
But there was one issue related to scheduled jobs - you could create them only at deployment time. We fixed this - you can now create scheduled jobs at runtime too.
With the latest changes to the TorqueBox codebase we can now use the full power of scheduled jobs with the flexibility of runtime scheduling. Let's start with an example.
TorqueBox::ScheduledJob.schedule('Counter', '*/10 * * * * ?')
This simple call will run the
Counter job every 10s. If
you think the job is executed too often, you can dynamically redefine the cron
expression and run it once a minute, for example:
TorqueBox::ScheduledJob.schedule('Counter', '0 * * * * ?')
schedule method waits until the job is fully deployed and returns
afterwards. If the job is not created in 30s the method returns
There are many other options, including customizing the job name or
description. Please refer to the RDoc documentation for the
The dynamic job replacement feature will work as long as the job name
is the same for all invocations. By default, the job name is set to
the job class name, so in the above example it'll be 'Counter'. When
the class name includes a module name (
the job name will be set to 'SomeModule.Counter'. We cannot have '::'
in the job name because of internal JBoss AS service naming
We suggest that you define the job name yourself:
TorqueBox::ScheduledJob.schedule('Counter', '0 * * * * ?', :name => 'job.counter')
This will make it easier to look it up later, for management.
It's also easy to do simple management of a scheduled job:
job = TorqueBox::ScheduledJob.lookup('job.counter') job.started? # true job.stop job.status # STOPPED job.start job.status # STARTED
And if you are tired of this job, you can remove it:
When we want to have even more control…
Sometimes the cron expression is not flexible enough to meet your needs. We hear you! Please welcome 'at' jobs!
Hi 'at' job!
There are different ways to schedule a job besides using cron expressions.
At, every, until
TorqueBox::ScheduledJob.at( 'Checker', :at => Time.now + 10, :every => 500, :until => Time.now + 70 )
This job will be run for the first time 10 seconds from now (
every 500 ms (
:every parameter) and will stop after 1 minute from the first
:at parameter is not set, it'll be set to
In, every, until
TorqueBox::ScheduledJob.at( 'Checker', :in => 10_000, :every => 500, :until => Time.now + 70 )
This style is very similar to the previous example with the difference being instead of specifying the time of the first job execution you define a delay (in ms) from now. This example is equal to the previous one in terms of the result.
At, repeat, every
TorqueBox::ScheduledJob.at( 'Checker', :at => Time.now + 10, :repeat => 5, :every => 1_000 )
This style focuses on the count of job executions. This job will be executed
for the first time 10s from now and repeated 5 times every 1s. Please note
that the total count of executions will be 6, since it executes once then
repeats 5 times. By default
:repeat is set to
0, so only one execution
You can replace the
:at parameter with
:in just like shown in the In,
every, until example.
And there's even more!
Just like the
schedule method, the
at method returns
depending on if the job was scheduled or timed-out.
Every 'at' job has many configurable options like defining the name,
description, or specifying the data to be injected to the job constructor
method. Everything is described in the RDoc documentation for
When will it be available?
We plan to include these new features in the next TorqueBox release. But if you're eager to test them - use the latest incremental build. It's already there!