Перейти к содержанию

Расширяемость

Эта страница описывает архитектурный подход QTasks к расширяемости: за счёт каких механизмов система адаптируется под новые сценарии, масштабируется и интегрируется с внешними библиотеками и фреймворками.

Расширяемость в QTasks определяется не количеством настроек, а структурой архитектуры: набором компонентов, их контрактами и возможностью внедрения дополнительного поведения через плагины.


Базовый принцип расширяемости

QTasks изначально спроектирован так, чтобы расширение происходило через композицию, а не через модификацию.

Основные факторы расширяемости:

  • замена или добавление компонентов;
  • использование плагинов;
  • соблюдение контрактов абстрактных классов;
  • передача данных через схемы.

Настройки играют вторичную роль и не являются основным механизмом масштабирования или интеграции.


Масштабирование через компоненты

Компоненты QTasks по умолчанию ориентированы на горизонтальное масштабирование.

Это означает, что система предполагает:

  • дублирование серверных экземпляров приложения;
  • совместную работу нескольких воркеров;
  • использование общего брокера и хранилища.

Изменение модели масштабирования достигается не через флаги конфигурации, а через:

  • замену конкретных реализаций компонентов;
  • изменение их поведения с помощью плагинов;
  • внедрение собственных стратегий распределения нагрузки.

Таким образом, масштабирование становится архитектурным решением, а не настройкой.


Плагины как механизм расширения

Плагины в QTasks используются для внедрения дополнительного поведения в существующие потоки выполнения.

Через плагины можно:

  • модифицировать жизненный цикл задач;
  • внедрять логирование, метрики и трассировку;
  • изменять стратегию выполнения без изменения компонентов;
  • добавлять интеграционные слои.

Плагины не нарушают архитектурные инварианты и не требуют изменения контрактов компонентов.


Интеграция с внешними библиотеками

QTasks допускает интеграцию с внешними библиотеками и фреймворками с минимальными ограничениями.

Это достигается за счёт:

  • отсутствия сигналов и глобальных диспетчеров;
  • минимального использования глобальных переменных;
  • жёсткого разделения ответственности между компонентами;
  • прозрачных потоков выполнения;
  • явного управления жизненным циклом.

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


Пример интеграции с FastAPI

Ниже приведён архитектурный пример использования QTasks совместно с FastAPI.

Определение задач

# tasks.py
from qtasks import AsyncRouter

router = AsyncRouter()

@router.task()
async def example_task(x: int, y: int) -> int:
    return x + y

Использование задачи в API

# api.py
from fastapi import FastAPI
from .tasks import example_task

app = FastAPI()

@app.get("/")
async def read_root():
    task = await example_task.add_task(1, 2, timeout=50)
    return {"result": task.returning}

Сервер QTasks

# qtasks_app.py
from qtasks.asyncio import QueueTasks
from .tasks import router as tasks_router

app = QueueTasks()
app.include_router(tasks_router)

if __name__ == "__main__":
    app.run_forever()

Архитектурный разбор примера

В этом сценарии:

  • API вызывает задачу напрямую через объект задачи, полученный из роутера;
  • вызов происходит через брокер (например, Redis), без прямой связи с сервером QTasks;
  • API ожидает результат через AsyncResult, так как указан timeout;
  • сервер QTasks может работать в другом процессе или на другом узле;
  • сервер знает о задаче благодаря include_router, а не за счёт жёсткой связки с API.

Клиенту достаточно передать задачу в брокер — остальная обработка происходит независимо.


Об управлении контекстом и глобальными переменными

В приведённом примере используется прямой доступ к задаче через роутер.

Если требуется отказаться от глобальных переменных, задача может быть объявлена через @app.task. В этом случае:

  • ссылка на app сохраняется внутри AsyncTask;
  • AsyncResult автоматически связан с нужным экземпляром приложения;
  • вызов задачи остаётся прозрачным для клиента.

Это подчёркивает, что выбор модели интеграции — архитектурное решение пользователя, а не ограничение QTasks.


Архитектурные инварианты

  • расширяемость достигается через компоненты и плагины;
  • масштабирование является следствием архитектуры, а не конфигурации;
  • QTasks не навязывает внешним приложениям свою модель управления;
  • интеграции не требуют вмешательства в ядро системы.

Такая модель позволяет использовать QTasks как основу для сложных и нестандартных сценариев без потери управляемости.