Как определить отмену задачи группой задач

Вопрос или проблема

Учитывая taskgroup и количество выполняемых задач, согласно документации по taskgroup, если какая-либо из задач вызывает ошибку, остальные задачи в группе будут отменены.

Если некоторые из этих задач должны выполнить очистку после отмены, то как можно определить внутри задачи, что она отменяется?

Надеялся, что в задаче будет вызвано какое-то исключение, но это не так:

script.py:

import asyncio

class TerminateTaskGroup(Exception):
    """Исключение, вызываемое для завершения группы задач."""

async def task_that_needs_to_cleanup_on_cancellation():
    try:
        await asyncio.sleep(10)
    except Exception:
        print('исключение поймано, выполняется очистка...')


async def err_producing_task():
    await asyncio.sleep(1)
    raise TerminateTaskGroup()


async def main():
    try:
        async with asyncio.TaskGroup() as tg:
            tg.create_task(task_that_needs_to_cleanup_on_cancellation())
            tg.create_task(err_producing_task())
    except* TerminateTaskGroup:
        print('обработка завершения main()')

asyncio.run(main())

При выполнении видно, что в task_that_needs_to_cleanup_on_cancellation() не возникает исключения:

$ python3 script.py 
обработка завершения main()

Ответ или решение

Для того чтобы обнаружить отмену задачи внутри группы задач в Python с использованием библиотеки asyncio, необходимо понимать, как работает механизм отмены и обработки исключений в контексте asyncio.TaskGroup. В данной ситуации, когда одна из задач вызывает исключение, остальным задачам будет отправлен сигнал на отмену, однако само по себе это событие не приводит к генерации исключения в каждой из оставшихся задач.

В вашем случае основная задача, task_that_needs_to_cleanup_on_cancellation, не получает информации об отмене, когда другая задача вызывает исключение. Однако есть способ обрабатывать отмены, используя специальные механизмы, предоставляемые asyncio.

Использование asyncio.CancelledError

Для корректного выполнения очистки при отмене задачи, вам следует включить обработку исключения asyncio.CancelledError. Это исключение возникает, когда задача отменена, и именно его нужно отловить для выполнения необходимых действий по очистке.

Вот как можно модифицировать вашу функцию task_that_needs_to_cleanup_on_cancellation для корректного выявления отмены:

import asyncio

class TerminateTaskGroup(Exception):
    """Исключение для завершения группы задач."""

async def task_that_needs_to_cleanup_on_cancellation():
    try:
        await asyncio.sleep(10)
    except asyncio.CancelledError:
        print('Задача отменена, выполняем очистку...')
        # Здесь вы можете добавить логику очистки
        raise  # Повторно возбуждаем исключение, чтобы завершить задачу

async def err_producing_task():
    await asyncio.sleep(1)
    raise TerminateTaskGroup()

async def main():
    try:
        async with asyncio.TaskGroup() as tg:
            tg.create_task(task_that_needs_to_cleanup_on_cancellation())
            tg.create_task(err_producing_task())
    except* TerminateTaskGroup:
        print('Обработка завершения в main()')

asyncio.run(main())

Объяснение изменения

  1. Обработка asyncio.CancelledError: Теперь в task_that_needs_to_cleanup_on_cancellation добавлена обработка исключения asyncio.CancelledError. Когда задача будет отменена, это исключение можно отловить и выполнить необходимую логику очистки.

  2. Вызов raise: После выполнения очистки рекомендуется снова вызвать raise, чтобы завершить задачу. Это важно, так как не нужно оставлять задачу в неясном состоянии после отмены.

  3. Ясная структура кода: Структура остается четкой и логичной, обеспечивая отличие между отменой задачи и настоящими исключениями, которые стоит обрабатывать по-другому.

Заключение

Способ обнаружения отмены задачи в группе задач asyncio заключается в правильной обработке исключения asyncio.CancelledError. Это позволяет выполнять необходимые действия по очистке в ответ на отмену, не теряя контроль над потоками исполнения. Мы надеемся, что информация была полезной для вас и прояснила, как правильно управлять задачами в асинхронной среде Python.

Оцените материал
Добавить комментарий

Капча загружается...