7

A very common need for an application is to run a script every X minutes/hours. Basically its nothing complicated, just some PHP code and a crontab entry.

Although I've written quite a few of those cronjobs in the past years I still haven't seen any best practices, at least not that much. As with every "background processing" so many things can go wrong especially in a production settings.

Among them:

  • an error occured during execution of the cron and the script died processing half of the data
  • the cronjob was accidently started twice by another process/by user error/whatever
  • the cronjob took way longer then expected and the script is called again although its not done processing data
  • etc.

What are some best pratices for writing rock-solid, robust cronjob scripts? Writing a lock file asserting that only one instance runs, extensive logging and monitoring in oder to prevent sending ten thousands of duplicate emails? What are your ideas?

Mob
  • 10,958
  • 6
  • 41
  • 58
Max
  • 15,693
  • 14
  • 81
  • 131
  • Interesting that you've posted this because I've been researching and wondering some of the same things. In my case, I'm really concerned about how to effectively implement exception handling in a shell script I'm writing. http://stackoverflow.com/questions/6961389/exception-handling-in-shell-scripting has some good info on that in case you're curious. I'm primarily a Java developer and exception handling there is very robust but seems harder in the *nix land. – Zack Macomber Feb 21 '12 at 20:55
  • this would depend on each and every script that is run, there is no generic answers, some need very robust error checking some need none ... –  Feb 21 '12 at 20:58
  • I bookmarked this question in anticipation of innovative answers with detailed justification of their benefits and drawbacks, and am pretty disappointed with the "This is what I do" answers. – nickb Feb 22 '12 at 00:26
  • See this related answer: [Managing log files created by cron jobs](https://stackoverflow.com/a/41756145/6862601). – codeforester Feb 04 '19 at 22:31

2 Answers2

2

Personally, the way I handle errors is to simply send STDERR to a log file, and then periodically check that file. An easy way to do that, is to append 2>/pathtolog to the crontab entry.

As far as having duplicates of the same program running, I prefer to have the script attempt to lock something (a file or a local network port). If it fails to obtain that lock, the script does not run. This way, if an existing script is currently running, a new one cannot obtain the identical lock.

GoldenNewby
  • 4,382
  • 8
  • 33
  • 44
0

There are lots of things you can do.

Set your cron scripts/binaries (scripts I guess since you mentioned they are written in PHP) to executable by owner or group depending on your needs.

If you want to make sure they're only executed by cron then make a cron user which is the only user that can execute the script. Then set that user to run it in your crontab entry.

In your cron script output significant things it does. Prepend your output with a timestamp / datestamp (depending on how often it runs). This makes it easy to grep for specific times in your log file.

Append your script's stdout to a log file by add >> /path/cron.log to your crontab entry.

You can also output the start time and end time of your cronjob so that you can analyzse the log every once in a while to make sure it is not too slow a process.

Your log file may look something like:

[ Tue Feb 20, 2012 ]:
[ Tue Feb 20, 2012 ]: Executing mycron.php
[ Tue Feb 20, 2012 ]: 
[ Tue Feb 20, 2012 ]: Running Query: ""SELECT SUM(`clicks`) FROM `matable`""
[ Tue Feb 20, 2012 ]: Running Query: ""INSERT INTO `History` (`date`, `total_clicks`) VALUES(CURDATE(), 12324123)
[ Tue Feb 20, 2012 ]: 
[ Tue Feb 20, 2012 ]: Finished executing mycron.php. Time taken: 3.462 seconds
[ Tue Feb 21, 2012 ]:
[ Tue Feb 21, 2012 ]: Executing mycron.php
[ Tue Feb 21, 2012 ]: 
[ Tue Feb 21, 2012 ]: Running Query: ""SELECT SUM(`clicks`) FROM `matable`""
[ Tue Feb 21, 2012 ]: Running Query: ""INSERT INTO `History` (`date`, `total_clicks`) VALUES(CURDATE(), 10376123)
[ Tue Feb 21, 2012 ]: 
[ Tue Feb 21, 2012 ]: Finished executing mycron.php. Time taken: 2.998 seconds

Except doing whatever it does instead of those two random queries, of course.

Paul
  • 139,544
  • 27
  • 275
  • 264
  • cronjob to check the log of your other cronjob, but what if that one fails? –  Feb 21 '12 at 21:13