Asynchrony in Ansible

Asynchrony in Ansible

Author of the article: Rustem Galiev

IBM Senior DevOps Engineer & Integration Architect. Official DevOps mentor and coach at IBM

Hello Habre! Let’s talk about asynchrony in Ansible, what it is and why you should use it.

Ansible has the concept of Async Actions. Ansible establishes connections to the target servers via SSH. This means that SSH connections remain active throughout the execution of the pull in the playbook. Sometimes we may need a long running task or process that exceeds the SSH timeout.

We may simply not want the SSH connection to remain active throughout the operation, or we may want to run multiple processes at the same time and check them later. Or another use case, perhaps to start one or more processes without even being able to check their status. All this can be achieved using asynchronous processes.

Let’s say that as part of our web application deployment, there is a script that monitors and performs some checks, say healthchecks, on the web server. It is on the way opt/monitor/checks.py. The scripts perform various checks, such as a stability check, to ensure that the web server remains online for at least five minutes without any problems. So obviously this script takes at least five minutes to complete.

We don’t want Ansible to maintain an SSH session until the script has finished executing. We want to tell Ansible that this is an asynchronous task (pull), so it needs to be run and checked, say, every minute. We use a directive async, to specify the maximum time during which we expect the pull to be performed. In our case, let’s say six minutes, given the other checks that need to be done.

Directive async tells Ansible that it’s an asynchronous task, so just let it run and check later.

And how often does Ansible check the status of the script?

By default, Ansible checks every 10 seconds. If we want to change this, we can use the poll directive. Checking every 10 seconds is too frequent for us, and we don’t want to wait for five minutes, because suddenly the script will fail after the first minute? We also don’t want to spend four minutes waiting for Ansible to check the status. So checking every minute seems like a good idea.

Set the Poll value to 60. Let’s add another task to monitor, for example, databases and give it six minutes to run and Poll every 60 seconds.

name: Deploy WebApp
hosts: webhost1
tasks:
   - command: /opt/monitor/checks.py
 	async: 360
 	poll: 60
	 
   - command: /opt/monitor/db.py
 	async: 360
 	poll: 60

What is going on here? When Ansible starts execution, it first executes the first task and will still wait for that task to complete.

Async doesn’t mean Ansible will run it and move forward. It will monitor the status of the script and wait until the specified time expires. In the case of 360 seconds.

So in this case it will run the first check, then wait about six minutes for it to complete, then run the second script to check the database and wait another six minutes for it to finish.

If we ran them in parallel, we could save a lot of time.

So we need to run the first task and have Ansible immediately jump to the second task and start the second check, and then wait for both tasks to complete at the end. This can be done by setting the poll value to zero.

By setting the poll value to zero, we ask Ansible not to wait, but to immediately proceed to the next pull.

In this case, Ansible will proceed to the next pull. However, immediately after starting the second task, it will terminate. We didn’t do anything to make Ansible wait for the pull to complete at the end.

To do this, you first need to register the result of the tasks in a variable. So, in this case, we log the result of the first task that monitors the web application into a variable named webapp_result. We also register the result of the second task, which consists in monitoring the database, in a variable db_result.

name: Deploy WebApp
hosts: webhost1
tasks:
   - command: /opt/monitor/checks.py
 	async: 360
 	poll: 0
 	register: webapp_result

   - command: /opt/monitor/db.py
 	async: 360
 	poll: 0
 	register: db_result

So we will get a new thrust to the end, which is called thrust status check. We use the module to check the status of the task async_status.

name: Deploy WebApp
hosts: webhost1
tasks:
   - command: /opt/monitor/checks.py
 	async: 360
 	poll: 0
 	register: webapp_result

   - command: /opt/monitor/db.py
 	async: 360
 	poll: 0
 	register: db_result

   - name: check_status_of_task
 	async_status: jid={{ webapp_result.ansible_job_id }}
 	register: job_result.finished
 	retries: 30

Thus, one of the parameters accepted by the module async_statusis the pull id and we could get the task id for the previous pull with webapp_resultwhich we have registered, and .ansible_job_id.

So here we pass the task id of the previous pull and then wait until that task is completed. However, it is worth remembering that not all modules support asynchrony.

Let’s look at another example of asynchronous operations.

We need to add a play to the playbook that will monitor the webapp for 5 minutes to make sure the app is ok, but we don’t want to keep the ssh connection open all that time. We also have a second player for monitoring the database, both players will run in parallel. We will register the execution results in the variable:

-
  name: Deploy a Postgres
  hosts: dbhost1
  roles:
	- python
	- postgres

-
  name: Deploy a Web Server
  hosts: webhost1
  roles:
	- python

-
  name: monitor_web_app_for_6_minutes
  hosts: web_server
  command: /opt/monitor/check.py
  async: 360
  poll: 0
  register: webapp_result

-
  name: monitor_db_for_6_minutes
  hosts: dbhost1
  command: /opt/monitor/db_check.py
  async: 360
  poll: 0
  register: database_result

In today’s world of software development, the need for fast and automated deployment is becoming increasingly important. However, using tools like Kubernetes is not always available or justified. Ansible is a flexible and powerful tool that can be used in any environment. I invite you to a free webinar where my colleagues will share with you their knowledge and experience in the field of using Ansible for application deployment. You’ll learn how to set up an automated deployment process using Ansible and Docker, bypassing the complexity and need for Kubernetes.

Related posts