Processing outside commands — python-heatclient — branch stable/2026.2
Branch
stable/2026.2@88120f11830d(5.3.0-2-g88120f1) — repository https://opendev.org/openstack/python-heatclient — analysed on 2026-11-01
There is no background processing: no bus consumer, no timer, no event listener, no thread. The inventory found 0 triggers and 0 RPC calls. The process ends with its command. What remains is client-side waiting inside a command, by HTTP polling. All of it talks to Heat, and Heat does the asynchronous work.
| Process | Trigger | Type | Purpose | Reads | Writes / emits | Defined at |
|---|---|---|---|---|---|---|
openstack | --wait on stack create, adopt, update, delete, suspend, resume, check, cancel | HTTP polling, 5 s by default; --poll exists on stack create only | wait for a final stack status | GET /stacks/{name}/events | event log on stdout | heatclient/common/event_utils.py:179 |
openstack | stack event list --follow | HTTP polling, fixed 5 s, never ends | follow the event log | same | event log on stdout | heatclient/osc/v1/event.py:193-217 |
heat | --poll on legacy commands | same function | same | events | event log | heatclient/v1/shell.py:143 |
| none | wait_for_events, on a websocket given by the caller | not polling | Python API helper; no caller in the package outside tests | websocket messages | event log | heatclient/common/event_utils.py:243 |
Client-side wait: poll_for_events
- Trigger:
--wait. Called atheatclient/osc/v1/stack.py:207,heatclient/osc/v1/stack.py:408,heatclient/osc/v1/stack.py:802,heatclient/osc/v1/stack.py:893,heatclient/osc/v1/stack.py:1198. - Emitter: none. Heat moves the stack; the client watches.
- Purpose: turn an accepted asynchronous operation into a blocking command.
- Data read:
GET /stacks/{name}/events?marker=<last id>&sort_dir=asc[observed, scenarios G02, G05]. - Flow (
heatclient/common/event_utils.py:205-240):stack update,deleteand the action commands first read the last event, withlimit=1&sort_dir=desc, to use its ID as the starting marker (heatclient/osc/v1/stack.py:395-399).stack createandadoptstart with no marker.- Each round fetches the events after the marker and prints them in log format.
- An event is a stack event when its
resource_nameequals the name given to the function, and itsphysical_resource_idequals the last segment of itsstacklink, or the link is absent (heatclient/common/event_utils.py:195-203). - A stack event with a final status ends the loop. With an action, final means
<ACTION>_COMPLETEor<ACTION>_FAILED. Without one (stack cancel), any*_COMPLETEor*_FAILED(heatclient/common/event_utils.py:183-187). - After 2 rounds with no event, it reads the stack (
GET /stacks/{name}?resolve_outputs=False) and checksstack_statusthe same way (heatclient/common/event_utils.py:229-238) [observed, scenario G04]. - It sleeps
poll_periodbetween rounds. The sleep is skipped when the round ends the loop.
- Concurrency and idempotency: polling is read-only. Interrupting the command does not cancel the operation on Heat [inferred].
- Error behaviour:
- A 404 on events becomes
CommandErrorwith Heat's message (heatclient/common/event_utils.py:167-170). stack delete --waittreats thatCommandErroras "the stack is gone", which is how the wait normally ends (heatclient/osc/v1/stack.py:804-805) [observed, scenario G08].- A 404 on the fallback
GETis not converted, sostack delete --waitthen reports a failure although the stack is gone (defect 8 in 02) [observed, scenario D09]. - A final
*_FAILEDmatching the action givesCommandErrorand exit 1 (heatclient/osc/v1/stack.py:210-211) [observed, scenario G03]. - Other HTTP errors and connection errors end the command, while the operation continues on Heat [inferred].
- A 404 on events becomes
- No time limit: the loop has no deadline and no retry count. A stack stuck in progress holds the command until it is interrupted.
- Name matching:
stack delete --waitpasses what the user typed. With an ID, no stack event matches, becauseresource_nameholds the name. The final status then comes only from the 404 or from the fallback after 2 empty rounds [inferred fromheatclient/common/event_utils.py:196; not run with an ID]. - Cost: one request per stack every 5 seconds, plus a lookup redirect for each fallback.
stack event list --follow
- Flow (
heatclient/osc/v1/event.py:193-217): refused unless the format islog; then get events after the marker, print them, sleep a fixed 5 s, forever. - Exit: only on
KeyboardInterruptorEOFError, with exit 0 [observed with a fake clock, scenario G15], or on an error from Heat.
Client-side recursion, not background work
stack event list --nested-depth N and stack failures list walk nested stacks inside the command, with sequential requests:
- Events: when the first event has no
root_stacklink, the client assumes the server ignorednested_depthand walks resources and events itself (heatclient/common/event_utils.py:86-120) [observed, scenarios G13, G14]. Marker and limit are then applied on the client. - Failures: one
GET /stacks/{id}/resourcesper failed nested stack, plus oneGET /software_deployments/{id}per failed deployment resource (heatclient/osc/v1/stack_failures.py:49-108) [observed, scenario G16].
Source: reverse-spec-python-heatclient/05-async-processing_stable-2026.2.md. The _rewrite/ and _inventory/ files are not published on the site.