python-trio / python-trio/trio

When building Channels on top of a bidirectional Stream, how should we handle closure?

Open
#895 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

communication design discussion
Dominant language
Python
Stars
7.3k
Forks
431
Avg merge
2d 17h
Merged PRs (30d)
6

Description

I came across a slightly tricky implication of the structure of Trio's stream ABCs today.

Suppose I'm implementing a channel that sends objects over a byte stream. Since I'd like to be able to use it on a unidirectional transport, for maximum flexibility I'll define StreamSendChannel to wrap a SendStream, and StreamReceiveChannel to wrap a ReceiveStream. All good so far.

Now I want to use these stream channels to send objects in both directions on a bidirectional transport that I have a Stream for. The subtyping relationships say any Stream is-a SendStream and also is-a ReceiveStream, so it looks like I can do this by wrapping the same Stream in two channels, one for sending and one for receiving. This works fine as long as the channel stays open, but since the two channels are independent, they can close independently, and then they clash over the calls they want to make to the stream's aclose(). The problem is that Stream.aclose() doesn't start meaning only SendStream.aclose() if you interpret the Stream as a SendStream -- it closes the receive side too.

I think this might be less confusing if Stream did not inherit SendStream and ReceiveStream. It could still define the same methods, and we could provide a helper for turning a Stream into a SendStream plus a ReceiveStream, that encapsulates the logic of:

  • send side aclose() calls send_eof() if impemented
  • receive side aclose() calls shutdown_read() if implemented (https://github.com/python-trio/trio/issues/823#issuecomment-459104932)
  • underlying stream aclose() only called when both send and receive sides have been closed
  • even if the underlying stream doesn't support a certain type of half-close, still provide its local semantics (by raising ClosedResourceError out of current and future operations)

This helper doesn't necessarily need to be provided by trio, and would be useful even if we don't change the inheritance hierarchy. I think it's probably not worth including in trio unless we change the inheritance hierarchy, so this issue is mostly about that question.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Read Trio's Stream, SendStream, and ReceiveStream ABC definitions first, then review the linked discussion in issue #823. Compare the inheritance change with the proposed bidirectional-stream helper; done requires a decided API direction and agreed closure semantics, but this issue does not name implementation files or tests.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
networking
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.