“Time Enough at Last”: A Simple Trick to Debug Cron Jobs

Published on December 29, 2016


Who's this for

  • Anyone still manually setting Cron entries—poor bastards.


  • Debugging unruly Cron entries can be a pain—until you unlock this built-in debugging tactic.

Task scheduling has become a foundational building block of even the simplest modern web apps. Whether you’re deleting old records, sending weekly updates, or processing payments, chances are excellent that you’ve come up against the need to automate some kind of periodic task.

Task scheduling is accomplished by setting Cron entries for each task you want to automate, but the challenges can be manifold:


Cron entry syntax is non-intuitive, to say the least. Here’s an example:

15 5 * * 3 path/to/commands/your_command.sh >> /dev/null

Each one of those asterisks represents a specific unit of time: minutes, hours, days, and so on, but unless you’ve memorized where each unit falls in the sequence, there is no way to know what interval you’re setting. (For those playing at home, that command is scheduled for 5:15am every Wednesday. Simple, right?)

Version Control

Cron entries are set within the server—not the source code. This means that for every development, testing, staging, or production environment you need, you’ll need to recreate your entries.

Every Host is a Unique Snowflake

Every host handles Cron entries a tiny bit differently, and documentation can be sporadic. You will inevitably face some trial and error when working on a new server, and attempting to debug a Cron entry once it’s started running—especially one that fires infrequently—can be a massive pain.

It’s that last point that stole several hours of my life last week. We were deploying a small Laravel app for a client that sends an administrative update at the end of every day. The launch went smoothly, but the updates weren’t sending. The app logs suggested the command was being fired, but the mailer logs showed no email being sent. I was lost.

And then, the answer, a white beam of light shining forth from an 18-year-old post on UNIXgeeks.com. Take a look again at the entry below:

15 5 * * 3 path/to/commands/your_command.sh >> /dev/null

In this—and just about every other Cron entry example on the internet—you’ll see /dev/null. This tells the Cron entry to discard any output from the command. But, if you configure this option, that output can become valuable debugging tool. Take a look at the updated entry:

15 5 * * 3 path/to/commands/your_command.sh >> /path/to/logs/cron.log

By specifying a path to a log file, you can capture your command’s output—including any errors it encounters. The logs revealed a typo in my Kernel.php file that was preventing the email from being sent. Fixing the typo fixed the issue.

If you’re lucky, you’re using a tool like Laravel Forge to manage your Cron entries, and you’ll never need to futz around with any of this. But, on the occasion that you do have to manually set a Cron entry, I hope this simple debugging trick saves you from the pain and anguish I experienced.