Skip to content

feat(client): add Channel::shutdown() to terminate the task explicitly - #194

Open
mdmzfzl wants to merge 2 commits into
stepfunc:mainfrom
mdmzfzl:feat/client-explicit-shutdown
Open

feat(client): add Channel::shutdown() to terminate the task explicitly#194
mdmzfzl wants to merge 2 commits into
stepfunc:mainfrom
mdmzfzl:feat/client-explicit-shutdown

Conversation

@mdmzfzl

@mdmzfzl mdmzfzl commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Problem

The client task completes only when every Channel clone has been dropped:
Receiver::recv() returns None once the last sender goes away, which becomes
SessionError::Shutdown.

That makes termination depend on how many handles exist and where they are held.
A caller that publishes a Channel somewhere outliving the task — a service
registry, a shared cache, anything with process lifetime — can never terminate
it, and awaiting the task's JoinHandle hangs.

Dropping handles in the right order is a convention every holder has to honour,
and nothing in the type system enforces it.

Change

Adds Channel::shutdown(), which sends shutdown as a command rather than
signalling it by releasing the last handle:

pub async fn shutdown(&self) -> Result<(), Shutdown>

Drop-based termination is unchanged, so this is additive — existing callers need
no changes.

Command gains a Shutdown variant, handled at both points where
reads its queue:

  • run_cmd, while connected, returning SessionError::Shutdown
  • fail_next_request, while disconnected or waiting to retry, r
    StateChange::Shutdown

Both already existed for the drop case, so this reuses the wind-down path rather
than adding a second one. Handling only the first would leave
solely while the device is reachable.

Semantics

  • Queued behind pending requests, so anything already in the queue is still
    processed — matching what dropping every handle does, since an
    buffer before reporting closure.
  • A transaction already in flight runs to completion, so the t
    within one response timeout of the last queued request.
  • Requests made after shutdown fail with RequestError::Shutdow
  • Signals the task rather than waiting on it; await ClientTask::run to observe
    completion.
  • Returns Err(Shutdown) if the task has already terminated, so a second call is
    harmless.

TCP and serial share ClientLoop, so both are covered with no
channel task.

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.

1 participant