Consequences of updating cron jobs within Ansible's playbook
Tags: ansible, tutorial, cron, engineeringmonday
Published: 2020-12-14 13:20:53

Hello fellow dev.to readers!

###Should you read this?

Today, I am writing about a smaller issue which occurred to us recently. More precisely, I will show you the pitfall and how we dealt with it.
If you have written a cron job within Ansible's playbook, but have never updated its values afterwards, you are a perfect reader for this post. Other than that, if you are interested in Ansible and want to learn something new, read on!

###Cron job example

```yaml
---
- hosts: all
  tasks:
    - name: Send emails about expiry dates
      cron:
        name: "Send expiry date emails (runs each day, 15 minutes after midnight)"
        minute: "15"
        hour: "0"
        job: "php path/to/console email-expiry-dates/send-email"
```

So, what do we have here?
It's a simple job which runs every day at 00:15 per server's time and executes a command which sends some emails.

If we would want to get a list of all cron's on the server, we could execute `crontab -l` on the server, and get something like this:
```bash
#Ansible: Send expiry date emails (runs each day, 15 minutes after midnight)
15 0 * * * php path/to/console email-expiry-dates/send-email
```

###Updating cron job

Let's say that server's current time zone is UTC+00:00, and a change request comes up for the existing cron job, something like:
> Emails should be delivered right after midnight in **New York's time zone**

What did we do to implement necessary changes? Updated cron job's execution **time**, but also its **name** (or we can say, the [description](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/cron_module.html#parameter-name)):

```yaml
---
- hosts: all
  tasks:
    - name: Send emails about expiry dates
      cron:
        name: "Send expiry date emails (runs each day, 15 minutes after midnight in New York's time zone)"
        minute: "15"
        hour: "5"
        job: "php path/to/console email-expiry-dates/send-email"
```

After deploying and listing server's cron jobs, we expected to have a single job as before, but with updated values, respectively. This was the actual result:

```bash
#Ansible: Send expiry date emails (runs each day, 15 minutes after midnight)
15 0 * * * php path/to/console email-expiry-dates/send-email

#Ansible: Send expiry date emails (runs each day, 15 minutes after midnight in New York's time zone)"
15 5 * * * php path/to/console email-expiry-dates/send-email
```

###What happened after update?

The result was 2 cron jobs. The old one stayed as is and the new one, with different parameters, was added to the list. Therefore, the same command was being executed 2 times a day, which definitely was not part of the acceptance criteria.

Since the *name* was changed, Ansible recognised this as a new cron job. This resulted in an unsynchronised state between server's and playbook's cron jobs.

###Fixing the unexpected problem

```yaml
---
- hosts: all
  tasks:
    - name: Old (Send emails about expiry dates)
      cron:
        name: "Send expiry date emails (runs each day, 15 minutes after midnight)"
        minute: "15"
        hour: "0"
        job: "php path/to/console email-expiry-dates/send-email"
        state: absent
    - name: Send emails about expiry dates
      cron:
        name: "Send expiry date emails (runs each day, 15 minutes after midnight in New York's time zone)"
        minute: "15"
        hour: "5"
        job: "php path/to/console email-expiry-dates/send-email"
```

As visible above, we tried to be in sync with the server, by adding another cron job (with old values). Besides that, we added an additional parameter to the old cron job - `state: absent`, which disabled its execution by removing it from the list of cron jobs on the server.

After deploying this fix to the server, this was a final result after listing cron jobs:

```bash
#Ansible: Send expiry date emails (runs each day, 15 minutes after midnight in New York's time zone)"
15 5 * * * php path/to/console email-expiry-dates/send-email
```

Yaay! A single cron job with all parameters set correctly 🎉

###Conclusion

Changing a cron job's *name* will not result in an update of the existing cron job. Its *name* is some sort of an ID, and therefore should not be changed (in most cases). But, what we can do, is play around with **tasks' name** property, since it will not lead to the problem we occurred :)

Do you have any tips regarding this topic? I would be glad to hear them!