|
Aria 2.0.0
C++23 MVVM framework (C++20 minimum) — reactive, coroutine-first, ABI-layered
|
Goal: when the user navigates away from a sub-view mid-request, cancel the in-flight async work so it never resumes against a destroyed view. This is the third lifetime axis (see docs/reference/lifecycle.md L-38.1; ROADMAP P1-H).
Aria already cancels in-flight work on VM destroy (ViewModelScope) and Navigator entry pop. The gap this recipe closes is the case where neither fires — a sub-view inside a still-living page.
BindingEngine::bind_view_lifetime(view, on_destroy_cb) runs on_destroy_cb exactly once, when the view is destroyed or the engine is cleared/destroyed — whichever comes first. It takes a plain std::function<void()>: the engine itself stays async-agnostic and never names an AsyncCommand type, so you wire the async side yourself in one explicit line (no hidden coupling) — even though the binding module as a whole does link aria-async for its ViewModelScope / Navigation facilities.
Now leaving the page mid-request flips the in-flight invocation's CancellationToken; the coroutine unwinds at its next probe (after a schedule_on hop) instead of resuming to write into a dead view.
AsyncResource::cancel() drops the in-flight write-back, re-arms a fresh CancellationSource (the resource stays usable on re-mount), and keeps the last data visible (stale-while-revalidate):
If the user comes back to the sub-view later, a fresh fetch() / refresh() works exactly as before — the previous value was preserved, so the view re-renders instantly while the new fetch runs.
test_binding_engine.cpp pins the primitive (fires on view destroy / on engine clear / exactly once). test_async_resource.cpp pins cancel() (drops in-flight write-back, re-arms, preserves last data). For the full destroy-race stress, see the binding_view_destroy_race fuzzer (L-32).