From 78d3810fdf7c579be5d9be8412844ae79d3f313b Mon Sep 17 00:00:00 2001 From: David Shrewsbury Date: Thu, 4 Mar 2021 14:06:27 -0500 Subject: [PATCH] Auto cleanup of async cache file (#73760) * Auto cleanup of async cache file * Add changelog --- changelogs/fragments/73760-async-cleanup.yml | 2 ++ .../rst/user_guide/playbooks_async.rst | 9 ++++++++ lib/ansible/executor/task_executor.py | 22 +++++++++++++++++++ test/integration/targets/async/tasks/main.yml | 19 ++++++++++++++++ 4 files changed, 52 insertions(+) create mode 100644 changelogs/fragments/73760-async-cleanup.yml diff --git a/changelogs/fragments/73760-async-cleanup.yml b/changelogs/fragments/73760-async-cleanup.yml new file mode 100644 index 00000000000..4d2790f465a --- /dev/null +++ b/changelogs/fragments/73760-async-cleanup.yml @@ -0,0 +1,2 @@ +bugfixes: + - Automatically remove async cache files for polled async tasks that have completed (issue https://github.com/ansible/ansible/issues/73206). diff --git a/docs/docsite/rst/user_guide/playbooks_async.rst b/docs/docsite/rst/user_guide/playbooks_async.rst index 50a2cd7be3f..50e13a7d530 100644 --- a/docs/docsite/rst/user_guide/playbooks_async.rst +++ b/docs/docsite/rst/user_guide/playbooks_async.rst @@ -62,6 +62,10 @@ To avoid timeouts on a task, specify its maximum runtime and how frequently you task when run in check mode. See :ref:`check_mode_dry` on how to skip a task in check mode. +.. note:: + When an async task completes with polling enabled, the temporary async job cache + file (by default in ~/.ansible_async/) is automatically removed. + Run tasks concurrently: poll = 0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -87,6 +91,11 @@ To run a playbook task asynchronously:: .. note:: Using a higher value for ``--forks`` will result in kicking off asynchronous tasks even faster. This also increases the efficiency of polling. +.. note:: + When running with ``poll: 0``, Ansible will not automatically cleanup the async job cache file. + You will need to manually clean this up with the :ref:`async_status ` module + with ``mode: cleanup``. + If you need a synchronization point with an async task, you can register it to obtain its job ID and use the :ref:`async_status ` module to observe it in a later task. For example:: - name: Run an async task diff --git a/lib/ansible/executor/task_executor.py b/lib/ansible/executor/task_executor.py index 3d8dcb306c0..55db1830162 100644 --- a/lib/ansible/executor/task_executor.py +++ b/lib/ansible/executor/task_executor.py @@ -795,6 +795,28 @@ class TaskExecutor: else: return dict(failed=True, msg="async task produced unparseable results", async_result=async_result) else: + # If the async task finished, automatically cleanup the temporary + # status file left behind. + cleanup_task = Task().load( + { + 'async_status': { + 'jid': async_jid, + 'mode': 'cleanup', + }, + 'environment': self._task.environment, + } + ) + cleanup_handler = self._shared_loader_obj.action_loader.get( + 'ansible.legacy.async_status', + task=cleanup_task, + connection=self._connection, + play_context=self._play_context, + loader=self._loader, + templar=templar, + shared_loader_obj=self._shared_loader_obj, + ) + cleanup_handler.run(task_vars=task_vars) + cleanup_handler.cleanup(force=True) async_handler.cleanup(force=True) return async_result diff --git a/test/integration/targets/async/tasks/main.yml b/test/integration/targets/async/tasks/main.yml index b5bebf10927..c8c12f6d601 100644 --- a/test/integration/targets/async/tasks/main.yml +++ b/test/integration/targets/async/tasks/main.yml @@ -42,6 +42,25 @@ - async_result.finished == 1 - async_result is finished +- name: assert temp async directory exists + stat: + path: "~/.ansible_async" + register: dir_st + +- assert: + that: + - dir_st.stat.isdir is defined and dir_st.stat.isdir + +- name: stat temp async status file + stat: + path: "~/.ansible_async/{{ async_result.ansible_job_id }}" + register: tmp_async_file_st + +- name: validate automatic cleanup of temp async status file on completed run + assert: + that: + - not tmp_async_file_st.stat.exists + - name: test async without polling command: sleep 5 async: 30