Depends¶
QTasks поддерживает управляемые зависимости для задач через механизм Depends.
Он позволяет объявлять параметры задачи так, чтобы их значения автоматически
создавались и корректно очищались в нужном контексте.
Пример использования Depends¶
from typing import Annotated
from contextlib import asynccontextmanager
from qtasks.plugins.depends import Depends, ScopeEnum
@asynccontextmanager
async def test_dep():
print("Open")
yield 123
print("Close")
@app.task
async def test(dep: Annotated[int, Depends(test_dep, scope=ScopeEnum.TASK)]):
print(dep)
При выполнении задачи вывод будет таким:
Open
123
Close
Что происходит:
- при старте задачи открывается контекст
test_dep(); - в тело задачи попадает значение
123; - при завершении задачи контекст закрывается, и печатается
Close.
Как работает Depends "под капотом"¶
Механизм Depends реализован во встроенном плагине воркера — (A)syncDependsPlugin.
Ниже — упрощённое описание шагов.
1. Поиск Depends в параметрах задачи¶
При подготовке к выполнению задачи плагин:
- проверяет наличие
Dependsкак явного значения параметра (dep = Depends(...)); - либо ищет его внутри
Annotated[..., Depends(...)](берёт последний элементAnnotated).
Если Depends найден, задача помечается как имеющая зависимость.
2. Создание контекста через (Async)ExitStack¶
Для управления жизненным циклом зависимости используется AsyncExitStack
(или ExitStack для синхронных задач):
- Плагин входит в контекст
test_dep()через стек контекстных менеджеров. - Полученное из
yieldзначение (в примере —123) сохраняется как значение параметра.
3. Обработка scope (области жизни зависимости)¶
Зависимость живёт в определённой "области" (scope), задаваемой ScopeEnum:
class ScopeEnum(Enum):
TASK = "task"
WORKER = "worker"
BROKER = "broker"
STORAGE = "storage"
GLOBAL_CONFIG = "global_config"
Логика:
TASK— контекст открывается при старте задачи и закрывается при её завершении.- остальные варианты (
WORKER,BROKER,STORAGE,GLOBAL_CONFIG) привязывают контекст к ресурсу компонента.
Технически это реализовано через триггеры:
TASK— закрывается на триггереtask_executor_task_close;- остальные — на триггерах завершения компонента:
"{component}_stop".
4. Подмена аргумента задачи¶
После получения значения из функции зависимости плагин:
- заменяет параметр задачи (
dep) на результатtest_dep(); - задача получает уже готовое значение (например, открытое подключение, объект сессии, число, конфиг и т.д.).
Зачем нужен Depends¶
Depends решает задачу управляемых зависимостей:
- создание и закрытие ресурсов в нужном контексте (на уровне задачи или компонента);
- отсутствие необходимости вручную работать с контекстными менеджерами внутри тела задач;
- единая точка описания зависимостей для разных задач.
Это удобный способ встроить подключение к БД, клиент внешнего сервиса, кеш, конфиг и другие ресурсы в задачи QTasks так, чтобы их жизненный цикл контролировался фреймворком.