Why use multiple lines of Elixir instead of a single line of cron? Cron has been a staple in the toolbox for developers making web applications. But with Elixir (or other languages based on the Erlang virtual machine) it is not as necessary anymore.

Using Elixir over cron has some advantages, including:

  • If your application runs, your scheduled job will run. The supervisor takes care of this.
  • If there are errors, they will be reported to the same place as other errors from your app.
  • One less runtime dependency - you don’t need cron.
  • The source code that schedules the job to run is in the same language and codebase as the rest of the app.

Before Elixir

Gratuitous photo of an old clock in Greenwich.

Imagine that it is the year 2000 and you are developing a web application using PHP. You want to periodically run a command to delete some temporary files from a directory. PHP application code is usually run when someone goes to their browser and clicks a link to you web site. However you do not want to run that command every time someone clicks a link to you website. So you decide to use cron. Just a single line of slightly cryptic code will make cron execute a command of your choosing. You manually add the cron entry to the server and verify that it works.

Then a year later you move the application to a new server. You make sure that PHP is there and that it has access to a MySQL server. Everything seems to be working fine. Shortly after you stop working on that application and new developers take over. They notice that server is starting to run out of space. A directory with files is growing and growing in size. They are not sure if the files can be deleted or not. Oops. When moving to the new server you forgot to add the cron job to the new server. However there were no warnings. And the PHP source code did not have any code that deleted the files.

The single line added to the crontab was a piece of the system. But because it manually added on a server and not added to the PHP source code, it was not part of the documented history of the system.

Of course instead of manually adding the cron tab, you can add the cron job to provisioning and deployment scripts which are tied to the application. The provisioning script would install things necessary for the cron job. Suddenly it is not just a single line of crontab entry that is necessary. Now it is that line, plus making sure that cron is present, plus code to update the crontab when there are changes.

A new solution

Fast forward to 2018. You are making a web app again. This time using Elixir. Again you need to periodically execute a command to delete temporary files. Instead of using cron, you use Elixir. With Elixir it is easy to add extra processes that can run code when you want. A very simple GenServer is all it takes to periodically run a command. If you prefer, there are libraries such as Quantum or SchedEx, that use the same kind of syntax as cron.

A single line of code can add it to the supervision tree of the application. This means that when the application runs - the code is executed. If something goes wrong, there are error messages. The code to schedule is no longer outside the code base. It no longer logs errors to a different place. It no longer requires cron to be available at runtime and the cron job to be set up and configured.

As with other uses of supervised processes in Elixir, you can trust that if the application is up, then the code is executed. If anything goes wrong there are errors that can be monitored in the same way as other errors in the system.

Comparing apples to oranges

What at first seems like “just one line in the crontab” is not the equivalent of adding a line to the Elixir source code. If provisioning is not already there for setting up the crontab and maintaining changes, that has to be added. This is just in order to make sure that the cron jobs are available and up to date.

When looking at the system as a whole the cron jobs are a part of what is necessary. If you already have procedures for developing, versioning and deploying code, you probably want the same for cron jobs. Going from not using cron to using cron is more than just manually logging on to a production server and running crontab -e if you want to have the same maintanability, version history and deployment process as your existing code.

New possibilities

Languages running on the BEAM (Erlang, Elixir, LFE etc.) add new possibilities compared to less concurrent languages that many developers have been using before. Suddenly things that required a dependency can now be done in the language itself. In fact in some cases, such as RabbitMQ, those dependencies were written in Erlang to begin with.

This means possibilities to reduce dependencies, simplify development, deployment, provisioning and monitoring.