Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Change Notification, Across the Languages

One contract, three surfaces, written once — the Python and Node books link here rather than restating it, so the three cannot drift.

The table

questionRustPythonNode
await the next installchanges().changed()changed_async() / async for changes()for await (const doc of config.changes())
installs and refusalsevents().next_event()events()events()
callback on installon_reload / on_reload_withon_reloadonReload / onReloadAsync
callback on refusalon_reload_failedvia events()via events()
triggeringedge: a wake per state change, never a queue replaysamesame
install deliverylatest-wins: ten installs while nothing awaited collapse to the newestsamesame
refusal deliverynever collapsed into a success — refusal-then-install yields both, refusal firstsamesame
slow consumermisses intermediate installs, never the newest; misses no refusal kind transitionsameonReloadAsync picks the policy: latest (abort in-flight), serial (FIFO all), every (fire-and-forget)
lossless stream?No, by design — see belownoonly serial, and only for the hooks it guards

Why delivery is edge-triggered and latest-wins

A configuration subscriber wants the newest state, not a history: a pool resizing to an intermediate size it will immediately resize away from is work, not correctness. So delivery is edge-triggered and collapsing — changes() resolves with whatever is current when the waiter runs, and generations may skip. Code that needs a total order reads generation (monotonic); code that needs an event log wants a message bus, which this is not and will not become.

Refusals are the exception to collapsing in one direction only: a refusal is never swallowed by the install that races it, because "the document was refused, then fixed" is operationally different from "the document changed". The reverse collapse (two refusals while nothing awaited → one wake) does hold — the count is on status().consecutive_failures and the monotonic refusals() counter, not in the stream.

What a failure delivers

FailureStatus: the category and the key path, never a message and never a value — the same discipline as every diagnostic surface here. Node's latest / serial / every backpressure vocabulary applies to failure events exactly as to installs.

Before the first install

A handle created before init() has seen nothing, so the initial install is its first event in every language — "wake me when configuration exists" is contract, not accident.