Expand description
One way to ask a service for something, and get an honest answer.
§Why this exists
The SDK offers twelve request_with_reply* functions across three outcome enums. They are all
correct; the problem is which one is shortest to type. request_with_reply_deadline returns
Option<Message>, so “the request never left” and “the deadline passed” arrive as the same
None - and those two demand opposite responses. Services that needed the distinction used to
reach for the longer _call_err variant to get it back; since every service moved onto this
library (2026-10-09), none calls _call_err directly - they call request_within, which rides it.
This module offers ONE way to ask, in four shapes: request and request_within (the default,
and the one to reach for), request_once (the same with no retry, for a caller that owns its own
recovery) and request_within_notice (for a person waiting at a prompt). The default keeps the
distinction and does the one retry that is provably safe, so that the easy path and the correct
path are the same path.
§What it does on your behalf, and what it refuses to
send ──▶ Reply you get the message
│
├─▶ SendFailed ──▶ REACQUIRE the peer by name, send ONCE more
│ (§14.3: a cap to a restarted service is stale forever,
│ and the obligation to notice is the client's)
│ └─▶ still failing: Err(Unreachable) nothing happened
│
├─▶ QueueFull ────▶ Err(Busy) nothing happened; pace yourself
│
├─▶ ReplyDead ────▶ Err(PeerDied) IT MAY HAVE HAPPENED; the peer is gone
│
└─▶ Timeout ──────▶ Err(OutcomeUnknown) IT MAY HAVE HAPPENEDIt never retries a timeout, or a peer that died holding the request. That is not caution, it
is correctness: a slow service is a live service, and re-sending a delete to one is not a retry,
it is a second delete whose failure looks like success. ReplyDead says the request was DELIVERED
(CLAUDE.md 8.6), so it is the same case with a dead peer instead of a slow one.
This diagram is request_within. request_within_notice with a callback follows it with two
differences - a peer that died holding the request reads as OutcomeUnknown, and a person can
press q - which its own documentation explains.
§ONE OF THESE IS SAFE FOR A SERVING CALLER, AND THE OTHER IS NOT
Read this before picking. The difference is not ergonomic, it decides whether a task that also SERVES clients can lose one of their requests (CLAUDE.md 8.2).
request_withinridesCallDeadline. The kernel matches the reply to this call’s own one-shot reply capability and leaves every other message queued. Safe for a serving task.request_within_noticerides the SDK’s_qhintvariant, which DRAINS the endpoint before sending (while self.try_recv().is_some() {}) and then waits with a plain timed receive, taking whatever lands next. NOT safe for a serving task: a client request arriving mid-wait is consumed and dropped.
That is deliberate rather than an oversight, and the SDK says so where it lives: _qhint
interleaves ON PURPOSE so it can notice a q keypress while waiting, and making it dequeue only
the reply would delete that. The honest fix is a bounded stash, which is real work and is not
done - so the limitation is recorded here (26.7) instead of being implied away.
It reaches further than this module. Every Fs::call goes through
request_within_notice, and so does every Net call, so a handle built
with Fs::with_notice or Net::with_notice is on that path too. Use the plain constructors in a
service that serves; with_notice is for a foreground command where a person is waiting and may
want to press q.
§Authority
Every call takes &ServiceContext. There is no global and no ambient handle. When this task holds
no send capability for peer, request_within asks the kernel’s name directory for one
(AcquireSendCap), exactly as it does for a stale one - and the kernel grants that only to a task
whose spawn request declared peer as a send peer, or that holds ACQUIRE_ANY (the shell, the
probes). Anyone else gets Unreachable. So this library widens nothing, but it is not true that
it never acquires: a task holding ACQUIRE_ANY can reach any named service through it.
Constants§
- DEFAULT_
SECS - How long to wait before calling an answer late, when the caller does not say.
- NOTICE_
AFTER_ SECS - How long a wait must last before the caller is told it is lasting.
Traits§
- Watch
- A COMMAND’s watch over its waits, lent by the program the operator is typing at (the shell).
Functions§
- request
- Ask
peerfor something and wait up toDEFAULT_SECSfor the answer. - request_
once request_withinwith NO retry: one send, one bounded wait, and the reason it failed.- request_
watched - A bounded request under a command’s
Watch:request_withinwhen the watch is not active, and otherwise a request that shows the command’s[q] quitand honours it. - request_
watched_ sifted request_watchedthat takes only the replymineaccepts, and drops any other while it waits. When the watch is not active it isrequest_within, which does not sift.- request_
within - Ask
peerfor something and wait up tosecsfor the answer. - request_
within_ notice - A bounded request with a callback fired once if the wait drags on - and, with a callback, NOT the
same machinery as
request_within.