Skip to content

Bounded-wait RPC companions: _within with timeout and cancellation - #276

Merged
turinglambdaai merged 2 commits into
mainfrom
feat/winrpc-within
Oct 16, 2026
Merged

turinglambdaai merged 2 commits into
mainfrom
feat/winrpc-within

Conversation

@turinglambdaai

Copy link
Copy Markdown
Owner

Closes #252.

What

The generated Windows/Linux C++ clients exposed only blocking calls, so hosts that poll or abandon an RPC spawned a detached std::thread per tick — threadly (MainWindow.Update.cpp:384) and movebit both churn one thread per 400 ms poll. Every RPC now also generates a bounded-wait companion:

std::optional<T> name_within(args, std::chrono::milliseconds rivet_timeout)
bool             name_within(args, std::chrono::milliseconds rivet_timeout)  // Void RPCs

The completion resolves a std::promise on the reader thread; the call waits up to the timeout and cancels the pending request through Backend::cancel on a miss — the existing request table does the bookkeeping, no new native thread. Backend and decoding errors still throw from the final get, matching the blocking contract. The naming collision check treats _within as a generated companion, so a schema RPC named foo_within fails generation instead of silently shadowing.

The checked-in Windows and Linux template headers gain the same shape in their own hand-written style, and docs/windows-native-window.md documents the sanctioned polling pattern: completions when a push model works; _within when the UI owns a tick loop — never a detached thread per tick.

Latent defect fixed

The new Void fixture exposed a latent generator defect: the Void async completion handler assigned into Result<void>, which has no value member — every generated header containing a Void RPC failed to compile (increment_within's fixture, log-line, now pins the corrected shape: the decode only validates arrival). Existing products with Void RPCs and generated _async calls were one regeneration away from this.

Tests

rivet/tests/codegen.rkt: the fixture gains a Void RPC (log-line), asserting increment_within/log_line_within shapes, cancel-on-miss returns, promise decode wiring, and the Void handler fix; existing snapshot-compatibility scenarios keep log-line present so their single-variable assertions stay single-variable. Full suite: 9868 pass.

The generated Windows/Linux C++ clients exposed only blocking calls, so
hosts that poll or abandon an RPC spawned a detached std::thread per
tick — threadly and movebit both churn one thread per 400 ms poll. Every
RPC now also generates a bounded-wait companion, name_within(arguments,
std::chrono::milliseconds): the completion resolves a promise, the call
waits up to the timeout, and a miss cancels the pending request through
Backend::cancel before returning. Void RPCs return bool (false = timed
out); other results return std::optional<T>. Backend and decoding errors
still throw from the final get, matching the blocking contract, and the
naming collision check treats _within as a generated companion so a
schema RPC named foo_within cannot collide.

The checked-in Windows and Linux template headers gain the same shape in
their own style (a shared unbox_string helper, greet_within and
increment_within), and docs/windows-native-window.md documents the
sanctioned polling pattern: completions when a push model works, _within
when the UI owns a tick loop — never a detached thread per tick.

Also fixes a latent generator defect the new Void fixture exposed: the
Void async completion handler assigned into Result<void>, which has no
value member — that generated header could not compile for any Void RPC
(log-line in the fixture now pins the shape: the decode only validates
arrival).
The taskboard's timing-start family (zero-argument RPCs) broke CI: the
generated signature was name_within(, std::chrono::milliseconds ...) —
a stray comma where an empty parameter list meets the timeout. The
within-params now emit the timeout alone when the RPC takes no
arguments. Verified against the taskboard schema locally: all 16
companions generate and both platform headers compile with the fixed
signatures; the test suite pins the zero-argument shape through the
health fixture RPC.
@turinglambdaai
turinglambdaai merged commit bb249d3 into main Oct 16, 2026
23 checks passed
@turinglambdaai
turinglambdaai deleted the feat/winrpc-within branch October 16, 2026 17:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Windows generated clients: cancellable / timeout-bounded RPC calls

1 participant