[PATCH 22/26] lucid: report async task progress
Daniel Gomez <[email protected]> Tue, 19 May 2026 15:28:19 +0200
| Newsgroups | dev.linux.lists.kdevops |
|---|---|
| Message-ID | <[email protected]> |
From: Daniel Gomez <[email protected]> Async tasks (those declared with an async and poll value) fire a separate family of callback hooks: v2_runner_on_async_poll during each polling interval and v2_runner_on_async_ok or v2_runner_on_async_failed when the job terminates. CallbackBase leaves all three as no-ops, and the normal v2_runner_on_ok and v2_runner_on_failed never fire for async jobs, so lucid's live display would show an async task as perpetually running from the moment it was dispatched. Routing async_ok and async_failed through the same _handle_result path as sync tasks collapses the two worlds: the running-task map clears, the dynamic display updates, failed_items and logging behave identically, and nothing downstream has to special-case async completion. Poll events land in their own handler and are gated at -vv because well-configured polling loops fire many times per job and would otherwise drown the screen. The log always captures them under an ASYNC POLL: prefix so the polling cadence is recoverable post-hoc. Generated-by: Claude AI Signed-off-by: Daniel Gomez <[email protected]> --- callback_plugins/lucid.py | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/callback_plugins/lucid.py b/callback_plugins/lucid.py index a8d0a9c1..83532e03 100644 --- a/callback_plugins/lucid.py +++ b/callback_plugins/lucid.py @@ -648,6 +648,46 @@ class CallbackModule(CallbackBase): """Host unreachable""" self._handle_result(result, "unreachable") + def v2_runner_on_async_poll(self, result): + """Async task polled and has not yet finished. + + Async tasks fire this hook repeatedly between dispatch and + completion. It is noisy by design, so we only emit on screen + at -vv or higher and always route through the log with a + consistent ASYNC POLL: prefix so post-hoc debugging can + reconstruct the polling cadence. + """ + host = result._host.name + ajid = result._result.get("ansible_job_id", "") + msg = f"ASYNC POLL: [{host}] job {ajid}" + if self._display.verbosity >= 2: + with self.output_lock: + self._display.display(msg, color=C.COLOR_VERBOSE) + self._write_to_log(msg) + + def v2_runner_on_async_ok(self, result): + """Async task finished successfully. + + Routing through _handle_result treats async completion the + same as a sync ok: the running-task map clears, the dynamic + display updates, and failed_items / logging behave + identically. Without this, lucid would show async tasks as + perpetually running because the normal on_ok never fires + for them. + """ + changed = result._result.get("changed", False) + status = "changed" if changed else "ok" + self._handle_result(result, status) + + def v2_runner_on_async_failed(self, result): + """Async task finished with a failure. + + Same routing as on_async_ok, but lands in the failed branch + of _handle_result so the dynamic display freezes and output + is surfaced the way a sync failure would be. + """ + self._handle_result(result, "failed") + def v2_runner_item_on_ok(self, result): """Loop item succeeded — log per-item command and output""" self._log_item_result(result) -- 2.53.0