The cron utility is the typical goto scheduling solution in unix/linux systems. Utilities like whenever allow us to take advantage of cron through an elegant and declarative pure ruby DSL.

The typical approach when using whenever for scheduling is to use deployment hooks to update the crontab from whenever's configuration during application deployment. However this approach falls short when the schedule is expected to be configurable at run time and especially if we want to give administrators fine grained controls over what is being scheduled and when.

Rather than coupling our code to a specific background processor which might in turn may be coupled with a specific transport system (like Sidekiq and Redis) it is advisable to rely instead (as much as possible) on ActiveJob API which provides a standardized API for background processing in Rails ecosystem.

The benefit of the event system being manageable through ActiveRecord is that integrated admin interfaces like ActiveAdmin and Administrate (which we might already have integrated in our existing applications) work out of the box and we get a complete schedule management interface with minimal extraneous boilerblate.

Note that while skipping rdoc and ri is purely a matter of convenience (I did not need them at the time) - the --pre flag is required, as of this writing, for installing Rails 5 as it is still in beta.

It may be tempting to just leave the in-memory adapter of ActiveJob in place but it should not be used in any production application. Rails guides explain it well enough:

Rails itself only provides an in-process queuing system, which only keeps the jobs in RAM. If the process crashes or the machine is reset, then all outstanding jobs are lost with the default async back-end. This may be fine for smaller apps or non-critical jobs, but most production apps will need to pick a persistent backend.

Here the first three columns correspond to accessors mandated by Clockwork. Name is primary for descriptive logging purposes (more on this below). frequency specifies the recurrance frequency in seconds. at signifies point of occurance within the recurrance span. Following are the valid formats:

HH:MM
H:MM
**:MM
HH:**
(Mon|mon|Monday|monday) HH:MM

The last two columns job_name and job_arguments identify the job to be triggered. As would become obvious below, we did not need to provide the job name through the database - it could be inferred at the runtime through any custom logic expressed in ruby. But having it in database leads to a straightforward and transparent implementation and management.

It may be tempting to just reuse the name field as the job_name as well, but it may obscure debugging when same job is being invoked as part of multiple events for different use cases. It is recommended to keep the name as something representative of the use case - eg. enterprise_plan_customers_sales_aggregation_trigger.

We would be using ActiveAdmin for our admin interface for managing events. As of this writing to use ActiveAdmin along with Rails 5 we need to use the master branch of ActiveAdmin.

While we will not go into elaboration of the ActiveAdmin DSL, most of the ideas should be applicable to alternative admin builders as well.

# Gemfile.rbgem'activeadmin',github:'activeadmin'

$ rails g active_admin:install

For now we skip authorization as well as authentication entirely - integrating ActiveAdmin with authentication systems is covered here and usage in conjugation with authorization systems is covered here in the official docs.