Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Run background tasks in a context manager #1141

Closed
joernheissler opened this issue Jul 7, 2019 · 3 comments
Closed

Run background tasks in a context manager #1141

joernheissler opened this issue Jul 7, 2019 · 3 comments

Comments

@joernheissler
Copy link

Hi,
many network protocols are multiplexed by nature, i.e. multiple logical connections share one physical connection. Examples include http2 (multiple requests in parallel), ssh (e.g. port forwardings), irc (chat with multiple persons).
Some background task is required which reads data from the physical connection and distributes it to the handler of the logical connection.

I'd like to see an easy way to create code like this:

async with Http2Client("server.example.net") as http:
    async with trio.open_nursery() as nursery:
        for path in {'/foo', '/bar', '/baz'}:
            nursery.start_soon(http.get, path)  # GET result is unused, for sake of brevity.

The Http2Client context manager would create a nursery and start a background task which reads data from the http server and handles it somehow.
The get method would send a request over the multiplexed connection and wait for the reply. The background task reads a reply from the server and sees e.g. "It's for the baz request" and then delivers it to the http.get foreground task for baz which will then return the result to the user.

As soon as the body of the context manager finishes, the background job is notified. In above example, it would cleanly shut down the http2 and TLS connections.

I wrote PoC code to create a simple IRC bot which talks to multiple people and echos everything they say back at them: https://gist.github.com/joernheissler/571f95e974ade2e5610dad9417ef8d49
(Needs python3.8; If you run it, please change the nicks)

Is that something which trio should have? And how should the API look like?

@belm0
Copy link
Member

belm0 commented Jul 8, 2019

See also #467

@njsmith
Copy link
Member

njsmith commented Jul 8, 2019

Yeah, this is definitely a common pattern. trio-websocket is a fairly mature example, and some relevant links are:

I'm not sure whether it makes sense for Trio to include some kind of helpers for this pattern, or not. Mostly I'm just not sure what those helpers would look like, or if it's possible to make ones that are useful and general enough to include :-). A basic implementation is just like:

@asynccontextmanager
async def open_irc(host, port, *, use_ssl=True, other_option=...):
    if use_ssl:
        stream = await trio.open_ssl_over_tcp_stream(host, port)
    else:
        stream = await trio.open_tcp_stream(host, port)
    async with trio.open_nursery() as nursery:
        yield IRCClient(nursery, stream, other_option=other_option, ...)
        nursery.cancel_scope.cancel()

That's short, and has a pretty high-density of protocol-specific stuff.

@oremanj
Copy link
Member

oremanj commented May 12, 2020

I think this is redundant with #467 in terms of next-actions, so closing.

@oremanj oremanj closed this as completed May 12, 2020
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

No branches or pull requests

4 participants