445 lines
16 KiB
Markdown
445 lines
16 KiB
Markdown
# PLBA
|
||
|
||
## 1. Общее описание сервиса и его назначение
|
||
|
||
`PLBA` (`Platform Runtime for Business Applications`) - это платформенный runtime для бизнес-приложений. Библиотека выносит из прикладного кода типовые инфраструктурные задачи: жизненный цикл приложения, запуск и остановку фоновых воркеров, загрузку конфигурации, health-check, tracing, логирование и control plane.
|
||
|
||
Назначение сервиса:
|
||
- дать единый каркас для запуска бизнес-модулей;
|
||
- отделить платформенные обязанности от предметной логики;
|
||
- упростить разработку сервисов с очередями, polling-обработчиками и фоновыми процессами;
|
||
- обеспечить наблюдаемость и управляемость runtime через health/status и HTTP control endpoints.
|
||
|
||
Текущая модель работы выглядит так:
|
||
1. приложение создаёт `RuntimeManager`;
|
||
2. runtime загружает конфигурацию;
|
||
3. применяется logging-конфигурация;
|
||
4. модуль приложения регистрирует очереди, обработчики, воркеры и health contributors;
|
||
5. `WorkerSupervisor` запускает все рабочие компоненты;
|
||
6. runtime агрегирует состояние, health и tracing;
|
||
7. control plane предоставляет снимок состояния и команды запуска/остановки.
|
||
|
||
`PLBA` особенно полезен для:
|
||
- почтовых ботов и интеграционных сервисов;
|
||
- event-driven и queue-driven приложений;
|
||
- фоновых бизнес-процессов;
|
||
- внутренних платформенных сервисов с единым operational-контуром.
|
||
|
||
## 2. Архитектура - диаграмма классов
|
||
|
||
```mermaid
|
||
classDiagram
|
||
class RuntimeManager {
|
||
+register_module(module)
|
||
+add_config_file(path)
|
||
+start()
|
||
+stop(timeout, force, stop_control_plane)
|
||
+status()
|
||
+current_health()
|
||
}
|
||
|
||
class ConfigurationManager {
|
||
+add_provider(provider)
|
||
+load()
|
||
+reload()
|
||
+get()
|
||
+section(name, default)
|
||
}
|
||
|
||
class ServiceContainer {
|
||
+register(name, service)
|
||
+get(name)
|
||
+require(name, expected_type)
|
||
+snapshot()
|
||
}
|
||
|
||
class ModuleRegistry {
|
||
+register_module(name)
|
||
+add_queue(name, queue)
|
||
+add_handler(name, handler)
|
||
+add_worker(worker)
|
||
+add_health_contributor(contributor)
|
||
}
|
||
|
||
class ApplicationModule {
|
||
<<abstract>>
|
||
+name
|
||
+register(registry)
|
||
}
|
||
|
||
class WorkerSupervisor {
|
||
+register(worker)
|
||
+start()
|
||
+stop(timeout, force)
|
||
+snapshot()
|
||
+healths()
|
||
+statuses()
|
||
}
|
||
|
||
class Worker {
|
||
<<abstract>>
|
||
+start()
|
||
+stop(force)
|
||
+health()
|
||
+status()
|
||
}
|
||
|
||
class QueueWorker {
|
||
+name
|
||
+critical
|
||
+start()
|
||
+stop(force)
|
||
+health()
|
||
+status()
|
||
}
|
||
|
||
class TaskQueue {
|
||
<<abstract>>
|
||
+publish(task)
|
||
+consume(timeout)
|
||
+ack(task)
|
||
+nack(task, retry_delay)
|
||
+stats()
|
||
}
|
||
|
||
class InMemoryTaskQueue {
|
||
+publish(task)
|
||
+consume(timeout)
|
||
+ack(task)
|
||
+nack(task, retry_delay)
|
||
+stats()
|
||
}
|
||
|
||
class TaskHandler {
|
||
<<abstract>>
|
||
+handle(task)
|
||
}
|
||
|
||
class TraceService {
|
||
+create_context(...)
|
||
+open_context(...)
|
||
+resume(task_metadata, operation)
|
||
+attach(task_metadata, context)
|
||
+info(message, status, attrs)
|
||
+warning(message, status, attrs)
|
||
+error(message, status, attrs)
|
||
}
|
||
|
||
class HealthRegistry {
|
||
+register(contributor)
|
||
+snapshot(worker_healths)
|
||
+payload(state, worker_healths)
|
||
}
|
||
|
||
class ControlPlaneService {
|
||
+register_channel(channel)
|
||
+start(runtime)
|
||
+stop()
|
||
+snapshot(runtime)
|
||
}
|
||
|
||
class LogManager {
|
||
+apply_config(config)
|
||
}
|
||
|
||
class FileConfigProvider {
|
||
+load()
|
||
}
|
||
|
||
RuntimeManager --> ConfigurationManager
|
||
RuntimeManager --> ServiceContainer
|
||
RuntimeManager --> ModuleRegistry
|
||
RuntimeManager --> WorkerSupervisor
|
||
RuntimeManager --> TraceService
|
||
RuntimeManager --> HealthRegistry
|
||
RuntimeManager --> ControlPlaneService
|
||
RuntimeManager --> LogManager
|
||
RuntimeManager --> ApplicationModule
|
||
ModuleRegistry --> ServiceContainer
|
||
ModuleRegistry --> Worker
|
||
ModuleRegistry --> TaskQueue
|
||
ModuleRegistry --> TaskHandler
|
||
WorkerSupervisor --> Worker
|
||
QueueWorker --|> Worker
|
||
QueueWorker --> TaskQueue
|
||
QueueWorker --> TaskHandler
|
||
QueueWorker --> TraceService
|
||
InMemoryTaskQueue --|> TaskQueue
|
||
ConfigurationManager --> FileConfigProvider
|
||
```
|
||
|
||
### Архитектурные слои
|
||
|
||
- `app_runtime.core` - оркестрация runtime, контейнер сервисов, регистрация модулей, типы состояния.
|
||
- `app_runtime.contracts` - абстракции для интеграции бизнес-приложений.
|
||
- `app_runtime.workers`, `queue`, `config`, `logging`, `health`, `tracing`, `control` - инфраструктурные адаптеры и платформенные сервисы.
|
||
- `plba` - публичный фасад, который реэкспортирует ключевые классы как API пакета.
|
||
|
||
## 3. Описание доступных модулей, их назначение, краткое устройство, примеры применения в бизнес приложениях
|
||
|
||
### `plba`
|
||
|
||
Публичный API пакета. Реэкспортирует `RuntimeManager`, `ApplicationModule`, `QueueWorker`, `InMemoryTaskQueue`, `TraceService`, `HealthRegistry`, `ControlPlaneService` и другие классы.
|
||
|
||
Краткое устройство:
|
||
- служит фасадом над `app_runtime`;
|
||
- упрощает импорт для прикладного кода;
|
||
- позволяет использовать пакет как библиотеку без знания внутренней структуры.
|
||
|
||
Пример применения:
|
||
- бизнес-сервис импортирует `create_runtime` и `ApplicationModule`, собирает свой модуль и запускает runtime.
|
||
|
||
### `app_runtime.core`
|
||
|
||
Основной orchestration-слой.
|
||
|
||
Ключевые классы:
|
||
- `RuntimeManager` - центральная точка запуска и остановки;
|
||
- `ConfigurationManager` - загрузка и merge конфигурации;
|
||
- `ServiceContainer` - DI-like контейнер платформенных сервисов;
|
||
- `ModuleRegistry` - регистрация очередей, обработчиков, воркеров и health contributors.
|
||
|
||
Краткое устройство:
|
||
- `RuntimeManager` создаёт и связывает инфраструктурные сервисы;
|
||
- при старте регистрирует health contributors, воркеры и поднимает control plane;
|
||
- `ModuleRegistry` связывает бизнес-модуль с runtime без жёсткой зависимости на конкретные реализации.
|
||
|
||
Примеры применения в бизнес-приложениях:
|
||
- CRM-интеграция с несколькими фоновых воркерами;
|
||
- сервис обработки заявок, где один модуль регистрирует очередь, handler и worker pool;
|
||
- back-office процесс с управляемым graceful shutdown.
|
||
|
||
### `app_runtime.contracts`
|
||
|
||
Набор абстракций для расширения платформы.
|
||
|
||
Ключевые контракты:
|
||
- `ApplicationModule`;
|
||
- `Worker`;
|
||
- `TaskQueue`;
|
||
- `TaskHandler`;
|
||
- `ConfigProvider`;
|
||
- `HealthContributor`;
|
||
- trace-related контракты.
|
||
|
||
Краткое устройство:
|
||
- бизнес-код реализует интерфейсы, а runtime работает только через контракты;
|
||
- это позволяет менять инфраструктуру без переписывания прикладной логики.
|
||
|
||
Примеры применения в бизнес-приложениях:
|
||
- реализовать свой `ApplicationModule` для почтового бота;
|
||
- подключить собственный `ConfigProvider` для БД или secrets storage;
|
||
- реализовать кастомный `Worker` для long-running polling процесса.
|
||
|
||
### `app_runtime.workers`
|
||
|
||
Модуль управления рабочими процессами.
|
||
|
||
Ключевые классы:
|
||
- `WorkerSupervisor` - запускает и останавливает набор воркеров;
|
||
- `QueueWorker` - стандартный worker для обработки задач из очереди.
|
||
|
||
Краткое устройство:
|
||
- `WorkerSupervisor` агрегирует health/status всех воркеров;
|
||
- `QueueWorker` поднимает нужное число потоков, читает задачи из `TaskQueue`, вызывает `TaskHandler`, делает `ack/nack` и обновляет operational-метрики.
|
||
|
||
Примеры применения в бизнес-приложениях:
|
||
- параллельная обработка входящих писем;
|
||
- обработка очереди заказов;
|
||
- фоновая генерация документов или актов.
|
||
|
||
### `app_runtime.queue`
|
||
|
||
Очереди задач.
|
||
|
||
Ключевой класс:
|
||
- `InMemoryTaskQueue`.
|
||
|
||
Краткое устройство:
|
||
- использует стандартный `Queue` из Python;
|
||
- хранит счётчики `published`, `acked`, `nacked`, `queued`;
|
||
- подходит как базовая реализация для разработки, тестов и простых сценариев.
|
||
|
||
Примеры применения в бизнес-приложениях:
|
||
- локальная очередь задач в небольшом внутреннем сервисе;
|
||
- тестовая среда без внешнего брокера;
|
||
- staging-сценарии для отладки worker pipeline.
|
||
|
||
### `app_runtime.config`
|
||
|
||
Подсистема загрузки конфигурации.
|
||
|
||
Ключевые классы:
|
||
- `FileConfigProvider`;
|
||
- `ConfigFileLoader`.
|
||
|
||
Краткое устройство:
|
||
- `ConfigurationManager` собирает данные из провайдеров;
|
||
- текущая штатная реализация читает YAML-файл;
|
||
- поддерживается глубокое слияние секций конфигурации.
|
||
|
||
Примеры применения в бизнес-приложениях:
|
||
- конфигурация платформы и прикладных модулей из `config.yml`;
|
||
- раздельное хранение `platform`, `log` и app-specific секций;
|
||
- подключение нескольких источников конфигурации с последующим merge.
|
||
|
||
### `app_runtime.logging`
|
||
|
||
Управление логированием.
|
||
|
||
Ключевой класс:
|
||
- `LogManager`.
|
||
|
||
Краткое устройство:
|
||
- применяет `dictConfig` из секции `log`;
|
||
- хранит последнюю валидную конфигурацию и пытается восстановиться при ошибке.
|
||
|
||
Примеры применения в бизнес-приложениях:
|
||
- единообразная настройка JSON-логов;
|
||
- переключение уровней логирования между окружениями;
|
||
- централизованная logging-конфигурация для нескольких модулей.
|
||
|
||
### `app_runtime.health`
|
||
|
||
Подсистема health aggregation.
|
||
|
||
Ключевой класс:
|
||
- `HealthRegistry`.
|
||
|
||
Краткое устройство:
|
||
- собирает health от воркеров и дополнительных contributors;
|
||
- агрегирует статус в `ok`, `degraded`, `unhealthy`;
|
||
- формирует payload для readiness/liveness и operational snapshot.
|
||
|
||
Примеры применения в бизнес-приложениях:
|
||
- показывать degraded, если обработка идёт с ошибками;
|
||
- маркировать сервис unhealthy при падении критичного worker;
|
||
- добавлять health внешней зависимости, например IMAP или ERP API.
|
||
|
||
### `app_runtime.tracing`
|
||
|
||
Подсистема трассировки выполнения.
|
||
|
||
Ключевые классы:
|
||
- `TraceService`;
|
||
- `TraceContextStore`;
|
||
- `NoOpTraceTransport`.
|
||
|
||
Краткое устройство:
|
||
- создаёт trace contexts;
|
||
- связывает source/queue/worker/handler через metadata;
|
||
- пишет контексты и сообщения через транспортный слой.
|
||
|
||
Примеры применения в бизнес-приложениях:
|
||
- трассировка обработки письма от polling до бизнес-handler;
|
||
- аудит прохождения заказа по pipeline;
|
||
- отладка проблемных задач в фоне.
|
||
|
||
### `app_runtime.control`
|
||
|
||
Control plane и HTTP-канал управления.
|
||
|
||
Ключевые классы:
|
||
- `ControlPlaneService`;
|
||
- `HttpControlChannel`;
|
||
- `ControlActionSet`.
|
||
|
||
Краткое устройство:
|
||
- публикует health/status и команды управления runtime;
|
||
- может поднимать HTTP endpoints для start/stop/status;
|
||
- строит snapshot состояния на основе `RuntimeManager`.
|
||
|
||
Примеры применения в бизнес-приложениях:
|
||
- административный endpoint для оператора;
|
||
- health endpoint для Kubernetes/nomad;
|
||
- runtime status для monitoring dashboard.
|
||
|
||
## 4. Установка - `git@git.lesha.spb.ru:alex/plba.git`
|
||
|
||
### Требования
|
||
|
||
- Python `3.12+`
|
||
- `pip`
|
||
- SSH-доступ к `git.lesha.spb.ru`
|
||
|
||
### Установка напрямую через `pip` из Git-репозитория
|
||
|
||
```bash
|
||
pip install "plba @ git+ssh://git@git.lesha.spb.ru/alex/plba.git"
|
||
```
|
||
|
||
Если нужна установка из конкретной ветки:
|
||
|
||
```bash
|
||
pip install "plba @ git+ssh://git@git.lesha.spb.ru/alex/plba.git@main"
|
||
```
|
||
|
||
Если нужна установка из конкретного тега или commit hash:
|
||
|
||
```bash
|
||
pip install "plba @ git+ssh://git@git.lesha.spb.ru/alex/plba.git@v0.1.0"
|
||
```
|
||
|
||
или
|
||
|
||
```bash
|
||
pip install "plba @ git+ssh://git@git.lesha.spb.ru/alex/plba.git@<commit-hash>"
|
||
```
|
||
|
||
### Установка в виртуальное окружение
|
||
|
||
```bash
|
||
python -m venv .venv
|
||
source .venv/bin/activate
|
||
pip install --upgrade pip
|
||
pip install "plba @ git+ssh://git@git.lesha.spb.ru/alex/plba.git"
|
||
```
|
||
|
||
### Локальная разработка
|
||
|
||
Если пакет нужно не только использовать, но и разрабатывать:
|
||
|
||
```bash
|
||
git clone git@git.lesha.spb.ru:alex/plba.git
|
||
cd plba
|
||
python -m venv .venv
|
||
source .venv/bin/activate
|
||
pip install -e .
|
||
```
|
||
|
||
### Быстрая проверка
|
||
|
||
```bash
|
||
python -c "import plba; print(plba.__all__[:5])"
|
||
```
|
||
|
||
### Минимальный пример использования
|
||
|
||
```python
|
||
from plba import ApplicationModule, InMemoryTaskQueue, QueueWorker, RuntimeManager, Task, TaskHandler
|
||
|
||
|
||
class PrintHandler(TaskHandler):
|
||
def handle(self, task: Task) -> None:
|
||
print(task.payload)
|
||
|
||
|
||
class DemoModule(ApplicationModule):
|
||
@property
|
||
def name(self) -> str:
|
||
return "demo"
|
||
|
||
def register(self, registry) -> None:
|
||
queue = InMemoryTaskQueue()
|
||
traces = registry.services.get("traces")
|
||
handler = PrintHandler()
|
||
queue.publish(Task(name="demo-task", payload={"id": 1}, metadata={}))
|
||
registry.add_worker(QueueWorker("demo-worker", queue, handler, traces))
|
||
|
||
|
||
runtime = RuntimeManager()
|
||
runtime.register_module(DemoModule())
|
||
runtime.start()
|
||
runtime.stop()
|
||
```
|