Sunday, 23 October 2016

How to set up e-mail notifications for Cron

Summary

Last week, I found myself setting up some jobs in a Unix environment (Centos 7) for which I wanted to get error email notifications and I ran into some troubles setting up the proper configuration, so I would like to take the chance and share the actions I took in case anyone finds him/herself in the same situation.

Please note that we are going to use Postfix as mail service here!

Initial Crontab setup

This was the setup I was facing, some jobs scheduled that might fail sometimes and one that will always fail as it was badly written:
$crontab -l

30 15 * * * java -jar /path_to_your_jar_app/job.jar
45 13 * * * /path_to_some_script/script.sh
45 19 * * * obviously_wrong_command
I wanted to be notified by email of any failure (and as I was using Cron, the expected behavior was to get an email  notification when either process returns a non-zero exit code).

This is an example of an email that should be generated for the above setup:
Message  1:
From cron_user@homepc  Sun Oct 23 19:45:01 2016
Delivered-To: john.doe.the.sysadmin@mailservice.com
From: "(Cron Daemon)" 
Subject: Cron  obviously_wrong_command
Content-Type: text/plain; charset=UTF-8
Auto-Submitted: auto-generated
Precedence: bulk
X-Cron-Env: XDG_SESSION_ID=3289
X-Cron-Env: XDG_RUNTIME_DIR=/run/user/3001
X-Cron-Env: LANG=en_US.UTF-8
X-Cron-Env: MAIL_TO=admin_user_alias
X-Cron-Env: SHELL=/bin/sh
X-Cron-Env: HOME=/home/cron_user
X-Cron-Env: PATH=/usr/bin:/bin
X-Cron-Env: LOGNAME=cron_user
X-Cron-Env: USER=cron_user
Date: Sun, 23 Oct 2016 19:45:01 +0200 (CEST)
Status: RO

/bin/sh: obviously_wrong_command: command not found
Keep reading if you want to get the same setup! 



Check that the email service is working

First, you should ensure that the basic mail setup is working properly. This can be done by manually generating an email for a system user (using the Unix mail system).
$echo "This is a test email" | mail -s "Test email" username
This example assumes that you have the mail program installed. Also, if you want to send an email to an external server, you should have connectivity. If you don´t get any email, check the email service logs here:
$sudo cat /var/log/maillog
If you get an error stating "postfix: fatal: parameter inet_interfaces: no local interface found for ::1" you have to edit /etc/postfix/main.cf  and change this line:
inet_interfaces = localhost
By this one:
inet_interfaces = all
Finally, just restart the Postfix service and try again.

Set the mail receiver(s) in Crontab

By default, Crontab sends an email to the user owner of the process. However, you might want to specify a specific user or alias, that will be in charge of monitoring all scheduled processes.

To do so, edit the Crontab configuration and add the MAILTO property with the alias of an hypothetical admin user:
$crontab -e

MAILTO=admin_user_alias
30 15 * * * java -jar /PATH_TO_YOUR_JAR/job.jar
45 13 * * * path_to_some_script/script.sh

Who is this admin user in reality? Actually is just an alias that we will use to setup the email address, outside of the local email system.

Edit /etc/aliases and add at the end of the file:
admin_user_alias:     john.doe.the.sysadmin@mailservice.com
And reload the aliases into the Postfix service:
postalias /etc/aliases
You can easily test this setup by adding an invalid command, scheduled close in time, and get the notification to your mail.

Notification of failed Java applications

In the previous example, I wrote an incorrect command, whose invokation returned and error code to the operating system. You can check that by running this:
[root@homepc]$ obviously_wrong_command
-bash: obviously_wrong_command: command not found
[root@homepc]$ echo $?
127

Now, when it comes to Java applications, there is a slight problem: Even when an Exception is thrown and the JVM is terminated, the process exits with a 0 code (success). Cron thinks everthing is OK and no notification in sent.

In order to overcome this, you have several options. One is, simply catching the Exception in the Main method and call the System.exit() method that allows you to return a specific numerical code:


And that´s it! This is the email received, which has part of the process output:
From cron_user@homepc  Sun Oct 23 20:10:02 2016
Delivered-To: john.doe.the.sysadmin@mailservice.com
From: "(Cron Daemon)"
Subject: Cron  java -jar /home/cron-user/myProgram.jar
Content-Type: text/plain; charset=UTF-8
Auto-Submitted: auto-generated
Precedence: bulk
X-Cron-Env: XDG_SESSION_ID=3293
X-Cron-Env: XDG_RUNTIME_DIR=/run/user/3001
X-Cron-Env: LANG=en_US.UTF-8
X-Cron-Env: MAIL_TO=admin_user_alias
X-Cron-Env: SHELL=/bin/sh
X-Cron-Env: HOME=/home/cron_user
X-Cron-Env: PATH=/usr/bin:/bin
X-Cron-Env: LOGNAME=cron_user
X-Cron-Env: USER=cron_user
Date: Sun, 23 Oct 2016 20:10:02 +0200 (CEST)
Status: R

java.io.IOException: I can not find a file!! Disaster!
        at org.victor.ferrer.crondemo.ExecutableMainClass.main(ExecutableMainClass.java:40)

Whenever there is something as bad as an unexpected termination, you should get an e-mail.

Although it works, I´m not a huge fan of this approach (i.e. using Cron for handling the scheduling) specially when it comes to use Java and Spring applications, so I am currently evaluating some other options (Spring Batch, Spring @Scheduling, etc,)

Which approach do you think is best? Which one do you use? Feel free to share it here!

No comments:

Post a Comment