summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Martz <matt@sivel.net>2021-04-05 15:51:12 +0200
committerGitHub <noreply@github.com>2021-04-05 15:51:12 +0200
commit33185c29abb266293f196da91a832d7d0a9eb90b (patch)
treec59080fcba791db063e4cccc736d5917028c3b7b
parentAdd ansible-test six constraint for Python 2.6. (diff)
downloadansible-33185c29abb266293f196da91a832d7d0a9eb90b.tar.xz
ansible-33185c29abb266293f196da91a832d7d0a9eb90b.zip
Implement workaround for stdout deadlock in multiprocessing shutdown (#74099)
-rw-r--r--changelogs/fragments/workerprocess-stdout-deadlock.yml3
-rw-r--r--lib/ansible/executor/process/worker.py13
2 files changed, 16 insertions, 0 deletions
diff --git a/changelogs/fragments/workerprocess-stdout-deadlock.yml b/changelogs/fragments/workerprocess-stdout-deadlock.yml
new file mode 100644
index 0000000000..8e7fed5d78
--- /dev/null
+++ b/changelogs/fragments/workerprocess-stdout-deadlock.yml
@@ -0,0 +1,3 @@
+bugfixes:
+- WorkerProcess - Implement workaround for stdout deadlock in multiprocessing shutdown
+ to avoid process hangs.
diff --git a/lib/ansible/executor/process/worker.py b/lib/ansible/executor/process/worker.py
index df3db35e4a..983df45bca 100644
--- a/lib/ansible/executor/process/worker.py
+++ b/lib/ansible/executor/process/worker.py
@@ -134,6 +134,19 @@ class WorkerProcess(multiprocessing_context.Process):
return self._run()
except BaseException as e:
self._hard_exit(e)
+ finally:
+ # This is a hack, pure and simple, to work around a potential deadlock
+ # in ``multiprocessing.Process`` when flushing stdout/stderr during process
+ # shutdown. We have various ``Display`` calls that may fire from a fork
+ # so we cannot do this early. Instead, this happens at the very end
+ # to avoid that deadlock, by simply side stepping it. This should not be
+ # treated as a long term fix. Additionally this behavior only presents itself
+ # on Python3. Python2 does not exhibit the deadlock behavior.
+ # TODO: Evaluate overhauling ``Display`` to not write directly to stdout
+ # and evaluate migrating away from the ``fork`` multiprocessing start method.
+ if sys.version_info[0] >= 3:
+ sys.stdout = os.devnull
+ sys.stderr = os.devnull
def _run(self):
'''