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

Компоненты: потоки и асинхронность

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

Речь идёт исключительно о режиме работы приложения как сервера. В клиентском режиме никакие фоновые потоки, циклы обработки или воркеры не запускаются.


Роль Starter в архитектуре

Для запуска QTasks в серверном режиме используется отдельный компонент — Starter.

Starter отвечает за первичную инициализацию потоков выполнения и управление жизненным циклом компонентов. Его задача — запустить систему и корректно её остановить, не вмешиваясь во внутреннюю логику самих компонентов.

Starter:

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

При этом Starter не определяет, каким образом компоненты будут работать после запуска. Модель выполнения, очереди, блокировки и асинхронность полностью определяются самими компонентами.


Использование Starter по умолчанию

Starter используется автоматически при запуске приложения через app.run_forever().

В зависимости от типа приложения применяется соответствующая реализация:

  • AsyncStarter — для qtasks.asyncio.QueueTasks;
  • SyncStarter — для qtasks.QueueTasks.

При необходимости Starter может быть заменён на пользовательскую реализацию при сохранении контракта.


Последовательность запуска

Starter запускает компоненты в строго определённом порядке.

Запуск

  1. Запускаются все зарегистрированные плагины:

  2. плагины самого Starter;

  3. плагины компонентов.

Для каждого плагина вызывается start().

  1. Запускается Worker через вызов:
worker.start(num_workers)
  1. Запускается Broker, которому передаётся ссылка на Worker:
broker.start(worker)

На этом этапе система считается запущенной и готовой к обработке задач.


Последовательность остановки

Остановка системы выполняется в обратном порядке и также контролируется Starter.

  1. Поочерёдно останавливаются основные компоненты:

  2. Broker;

  3. Worker;
  4. Storage;
  5. GlobalConfig (если присутствует).

Для каждого компонента вызывается stop(). 1.1. Если в процессе работы был создан _global_loop, он также останавливается. 2. После остановки компонентов останавливаются все запущенные плагины через stop().

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


Note

Компонент GlobalConfig является необязательным основным компонентом. Несмотря на наличие реализации по умолчанию, он может отсутствовать.
Во всех местах, где требуется его запуск или остановка, необходимо предварительно проверять, что компонент существует (не равен None).


Архитектурная схема запуска компонентов

В упрощённом виде схема запуска и зависимости компонентов выглядят следующим образом:

Starter
  ├── Worker
  ├── Broker
  │     └── Storage
  │           └── GlobalConfig (опционально)

Эта схема отражает только иерархию запуска и зависимости, но не определяет внутренние модели выполнения.


Асинхронность как локальное свойство

В архитектуре QTasks асинхронность не является глобальным состоянием приложения.

  • Starter лишь инициирует запуск компонентов;
  • каждый компонент самостоятельно определяет:

  • использовать ли event loop;

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

Это позволяет сочетать синхронные и асинхронные компоненты в рамках одной системы и адаптировать модель выполнения под конкретную инфраструктуру.


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

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

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