pythonpython-asynciopython-trio

Python - How to cancel a specific task spawned by a nursery in python-trio


I have an async function that listens on a specific port. I want to run the function on a few ports at a time and when the user wants to stop listening on a specific port, stop the function listening on that port.

Previously I was using the asyncio library for this task and I tackled this problem by creating tasks with a unique id as their name.

asyncio.create_task(Func(), name=UNIQUE_ID)

Since trio uses nurseries to spawn tasks, I can see the running tasks by using nursery.child_tasks but the tasks don't have a way to name them and even a way to cancel a task on demand

TL;DR

Since trio doesn't has a cancel() function that cancels a specific task, how can I manually cancel a task.


Solution

  • Easy. You create a cancel scope, return that from the task, and cancel this scope when required:

    async def my_task(task_status=trio.TASK_STATUS_IGNORED):
        with trio.CancelScope() as scope:
            task_status.started(scope)
            pass  # do whatever
    
    async def main():
        async with trio.open_nursery() as n:
            scope = await n.start(my_task)
            pass  # do whatever
            scope.cancel()  # cancels my_task()
    

    The magic part is await n.start(task), which waits until the task calls task_status.started(x) and returns the value of x (or None if you leave that empty).