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

Should Nursery.start_soon return the trio.hazmat.Task object #1373

Closed
pipermerriam opened this issue Jan 22, 2020 · 6 comments
Closed

Should Nursery.start_soon return the trio.hazmat.Task object #1373

pipermerriam opened this issue Jan 22, 2020 · 6 comments

Comments

@pipermerriam
Copy link

In asyncio land a call to asyncio.ensure_future(my_coro()) returns a Task object. This object is the same object that would be returned if you called asyncio.current_task() from within my_coro().

In trio land, Nursery.start_soon(my_coro) doesn't have a return value. The only way to get the running task that I could figure out was from within the running task by calling trio.hazmat.current_task(). This doesn't allow the scheduler to know about the task up-front.

Was this an intentional design decision? I dug through issues and didn't find anything. Looking at the code it seems like a trivial thing to do by adding a single return statement here:

GLOBAL_RUN_CONTEXT.runner.spawn_impl(async_fn, args, self, name)

@njsmith
Copy link
Member

njsmith commented Jan 22, 2020

Yes, it's intentional:

  • start_soon returns None, but start returns a user-controlled value – if start_soon returned a task, then what should start return?
  • Trio Task objects aren't really useful to start_soon callers. What were you hoping to do with the task if you had it? This isn't like asyncio where you can await the task (because having futures opens up a huge can of design worms), or call .cancel() on it (because we use cancellation scopes instead). There's a reason that Task lives in hazmat :-)

@pipermerriam
Copy link
Author

I don't feel strongly about this so no need to defend your decision on the start_soon API.

In case you're curious, here is the library I'm working in:

https://github.com/ethereum/async-service/

The library provides a high level abstraction over using trio or asyncio for writing what the library calls a Service which can just be thought of as an encapsulation of some program logic that typically as async components. Each Service implements a single run() method. Services can run "tasks" in the background. These tasks form a DAG with the run() task at the root and each spawned background job living under the parent that spawned it.

The need fo a reference to the trio.hazmat.Task object comes from the libraries cancellation semantics. Supposing a Service runs three tasks in the hierarchy A -> B -> C with A as the root task spawning B and B spawning C, then the cancellation will cancel them in the order C -> B -> A, ensuring that no task is issued a cancellation until all of its children have been cleaned up.

I was able to work around this just fine using trio.hazmat.current_task from within the running task. Just would have been slightly m ore convenient to be able to gain a reference to the queued task up-front.

@pquentin
Copy link
Member

@pipermerriam Thanks for opening this issue! Today I learned more about trio (and async-service).

I don't feel strongly about this so no need to defend your decision on the start_soon API.

I don't think @njsmith was "defending" the decision, my reading was that he simply explained the rationale as you asked for it in your initial post. Did you feel that the tone was inappropriate?

@pipermerriam
Copy link
Author

I was merely trying to signal that my reply wasn't intended to push for the API to change (but rather to explain the why behind my opening the issue). 😄

@pquentin
Copy link
Member

@pipermerriam Thanks for clarifying!

Oh, I was about to forgot: nice avatar! 😄

@njsmith
Copy link
Member

njsmith commented Jan 24, 2020

Yeah, I'm a big fan of documenting design rationales like this; I feel like if you can't articulate the reason for something, then that's a good hint it might be wrong :-). So no worries about that.

The need fo a reference to the trio.hazmat.Task object comes from the libraries cancellation semantics. Supposing a Service runs three tasks in the hierarchy A -> B -> C with A as the root task spawning B and B spawning C, then the cancellation will cancel them in the order C -> B -> A, ensuring that no task is issued a cancellation until all of its children have been cleaned up.

Hmm yeah this has come up a few times. I'm not sure where we talked about it, but one idea was to have a version of a nursery that shields all background tasks from cancellation until the main with block closes, and then when it closes it automatically cancels all of them.

I'm still confused about how trio.hazmat.Task objects are useful to you here, since they don't have any methods that let you control cancellation :-)

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

3 participants