Summary
Remove four behaviour-preserving shared-ownership operations that do not correspond to independent lifetimes.
This is the low-risk first implementation slice of Epic #635 and ADR 011 proposal #636. It should remain reviewable as a local refactor rather than waiting for the prepared-application or client-pool redesigns.
Changes
1. Borrow the connection actor cancellation token
ConnectionActor::next_event currently clones self.shutdown and passes the owned token to wait_shutdown, which calls cancelled_owned().
Refactor the select loop to borrow the token and await CancellationToken::cancelled() for the duration of one loop iteration. Extract disjoint field references before tokio::select! as needed to satisfy the borrow checker.
Do not change cancellation precedence or the existing biased branch order.
2. Send through the borrowed push sender
PushHandle::push_with_priority currently calls tx.clone().send(frame).await even though mpsc::Sender::send takes &self.
Call tx.send(frame).await directly. Preserve error mapping, rate-limit ordering, and queue backpressure.
3. Store the connection-local fragmenter by value
ConnectionActor is the sole owner of its configured fragmenter, but stores Option<Arc<Fragmenter>>.
Change this to Option<Fragmenter> and borrow it during frame fragmentation. Do not change the public Fragmenter concurrency contract or replace its atomic message-id source in this issue; a connection-local non-atomic allocator can be evaluated separately with evidence.
4. Store the middleware function directly in FnService
FromFn::transform clones F, places it in a fresh Arc, and creates one FnService that is never cloned.
Store F directly in FnService<S, F> and invoke it by reference. Preserve all current Send + Sync + 'static bounds and middleware behaviour.
Acceptance criteria
Tests
Add or retain focused tests that make the borrowed-lifetime behaviour visible indirectly:
- repeated actor events followed by cancellation terminate promptly;
- cancellation already requested before
run still exits immediately;
- sender closure returns
PushError::Closed without cloning requirements;
- fragmenter state advances across multiple frames owned by one actor;
- middleware functions with captured immutable state still execute correctly.
Non-goals
- Redesigning
CancellationToken use across independent tasks.
- Removing legitimate shared state from
PushHandle.
- Introducing a connection-local non-atomic fragment ID allocator.
- Changing the middleware trait or public
from_fn API.
References
Summary
Remove four behaviour-preserving shared-ownership operations that do not correspond to independent lifetimes.
This is the low-risk first implementation slice of Epic #635 and ADR 011 proposal #636. It should remain reviewable as a local refactor rather than waiting for the prepared-application or client-pool redesigns.
Changes
1. Borrow the connection actor cancellation token
ConnectionActor::next_eventcurrently clonesself.shutdownand passes the owned token towait_shutdown, which callscancelled_owned().Refactor the select loop to borrow the token and await
CancellationToken::cancelled()for the duration of one loop iteration. Extract disjoint field references beforetokio::select!as needed to satisfy the borrow checker.Do not change cancellation precedence or the existing biased branch order.
2. Send through the borrowed push sender
PushHandle::push_with_prioritycurrently callstx.clone().send(frame).awaiteven thoughmpsc::Sender::sendtakes&self.Call
tx.send(frame).awaitdirectly. Preserve error mapping, rate-limit ordering, and queue backpressure.3. Store the connection-local fragmenter by value
ConnectionActoris the sole owner of its configured fragmenter, but storesOption<Arc<Fragmenter>>.Change this to
Option<Fragmenter>and borrow it during frame fragmentation. Do not change the publicFragmenterconcurrency contract or replace its atomic message-id source in this issue; a connection-local non-atomic allocator can be evaluated separately with evidence.4. Store the middleware function directly in
FnServiceFromFn::transformclonesF, places it in a freshArc, and creates oneFnServicethat is never cloned.Store
Fdirectly inFnService<S, F>and invoke it by reference. Preserve all currentSend + Sync + 'staticbounds and middleware behaviour.Acceptance criteria
ConnectionActor::next_eventperforms noCancellationTokenclone per event-loop iteration.PushHandle::push_with_priorityperforms no sender clone immediately beforesend.ConnectionActorcontainsOption<Fragmenter>, notOption<Arc<Fragmenter>>.FnServiceownsFdirectly and allocates noArc<F>during transformation.Tests
Add or retain focused tests that make the borrowed-lifetime behaviour visible indirectly:
runstill exits immediately;PushError::Closedwithout cloning requirements;Non-goals
CancellationTokenuse across independent tasks.PushHandle.from_fnAPI.References
src/connection/mod.rssrc/connection/polling.rssrc/push/queues/handle.rssrc/middleware.rs