Правки описания

This commit is contained in:
2026-03-04 10:38:21 +03:00
parent de787ce7ee
commit c5a78d80d4
6 changed files with 890 additions and 446 deletions

867
README.md
View File

@@ -1,469 +1,444 @@
# PLBA
`PLBA` is a reusable platform runtime for business applications.
It solves platform concerns that should not live inside domain code:
- application lifecycle
- worker orchestration
- configuration loading from YAML
- tracing
- health aggregation
- runtime status reporting
- HTTP control endpoints
- logging configuration
Business applications depend on `plba` as a package and implement only their own business behavior.
## Architecture
Current PLBA architecture is built around one core idea:
- the runtime manages a set of application workers
A worker is any runtime-managed active component with a unified lifecycle:
- `start()`
- `stop(force=False)`
- `health()`
- `status()`
This means PLBA does not require separate platform categories like `source` and `consumer`.
If an application needs polling, queue processing, listening, scheduled work, or another active loop, it is implemented as a worker.
### Main runtime model
1. application creates `RuntimeManager`
2. runtime loads configuration
3. runtime applies logging configuration
4. application module registers workers and supporting services
5. runtime starts all workers
6. workers execute business-related loops or processing
7. runtime aggregates health and status
8. runtime stops workers gracefully or forcefully
## Core concepts
### `ApplicationModule`
File: [application.py](/Users/alex/Dev_projects_v2/apps/plba/src/app_runtime/contracts/application.py)
Describes a business application to the runtime.
Responsibilities:
- provide module name
- register workers
- register queues if needed
- register handlers if needed
- register health contributors
- compose application-specific objects
`ApplicationModule` does not run the application itself.
It only declares how the application is assembled.
### `Worker`
File: [worker.py](/Users/alex/Dev_projects_v2/apps/plba/src/app_runtime/contracts/worker.py)
The main runtime-managed contract.
Responsibilities:
- start its own execution
- stop gracefully or forcefully
- report health
- report runtime status
This is the main extension point for business applications.
### `TaskQueue`
File: [queue.py](/Users/alex/Dev_projects_v2/apps/plba/src/app_runtime/contracts/queue.py)
Optional queue abstraction.
Use it when application workers need buffered or decoupled processing.
PLBA does not force every application to use a queue.
Queue is one supported pattern, not the foundation of the whole platform.
### `TaskHandler`
File: [tasks.py](/Users/alex/Dev_projects_v2/apps/plba/src/app_runtime/contracts/tasks.py)
Optional unit of business processing for one task.
Useful when a worker follows queue-driven logic:
- worker takes a task
- handler executes business logic
### `TraceService`
File: [service.py](/Users/alex/Dev_projects_v2/apps/plba/src/app_runtime/tracing/service.py)
Platform trace service.
Responsibilities:
- create trace contexts
- resume trace from task metadata
- write context records
- write trace messages
Business code should use it as a platform service and should not implement its own tracing infrastructure.
### `HealthRegistry`
File: [registry.py](/Users/alex/Dev_projects_v2/apps/plba/src/app_runtime/health/registry.py)
Aggregates application health.
PLBA uses three health states:
- `ok` — all critical parts work
- `degraded` — application still works, but there is a problem
- `unhealthy` — application should not be considered operational
### Runtime status
File: [types.py](/Users/alex/Dev_projects_v2/apps/plba/src/app_runtime/core/types.py)
Status is separate from health.
Current runtime states:
- `starting`
- `idle`
- `busy`
- `stopping`
- `stopped`
Status is used for operational lifecycle decisions such as graceful shutdown.
### `ControlPlaneService`
Files:
- [service.py](/Users/alex/Dev_projects_v2/apps/plba/src/app_runtime/control/service.py)
- [http_channel.py](/Users/alex/Dev_projects_v2/apps/plba/src/app_runtime/control/http_channel.py)
Provides control and observability endpoints.
Currently supported:
- health access
- runtime start action
- runtime stop action
- runtime status action
### `ConfigurationManager`
Files:
- [configuration.py](/Users/alex/Dev_projects_v2/apps/plba/src/app_runtime/core/configuration.py)
- [file_loader.py](/Users/alex/Dev_projects_v2/apps/plba/src/app_runtime/config/file_loader.py)
- [providers.py](/Users/alex/Dev_projects_v2/apps/plba/src/app_runtime/config/providers.py)
Loads and merges configuration.
Current built-in source:
- YAML file provider
### `LogManager`
File: [manager.py](/Users/alex/Dev_projects_v2/apps/plba/src/app_runtime/logging/manager.py)
Applies logging configuration from config.
Current expectation:
- logging config lives in the `log` section of YAML
## Available platform services
PLBA currently provides these reusable services.
### 1. Runtime lifecycle
Service:
- `RuntimeManager`
What it gives:
- startup orchestration
- worker registration and startup
- graceful stop with timeout
- force stop
- status snapshot
Example use:
- start `mail_order_bot`
- stop it after active email processing is drained
### 2. Worker supervision
Service:
- `WorkerSupervisor`
What it gives:
- unified worker orchestration
- aggregated worker statuses
- aggregated worker health
- stop coordination
Example use:
- run one polling worker and three processing workers in the same application
### 3. Queue support
Services:
- `TaskQueue`
- `InMemoryTaskQueue`
- `QueueWorker`
What it gives:
- buffered processing
- decoupling between task production and task consumption
- worker concurrency for task handling
Example use:
- worker A polls IMAP and pushes tasks to queue
- worker B processes queued email tasks with concurrency `3`
### 4. Configuration
Services:
- `ConfigurationManager`
- `FileConfigProvider`
- `ConfigFileLoader`
What it gives:
- YAML config loading
- config merging
- access to platform and application config
Example use:
- load `platform` section for runtime
- load `mail_order_bot` section for app-specific config
### 5. Tracing
Services:
- `TraceService`
- `TraceTransport`
- `NoOpTraceTransport`
What it gives:
- trace context creation
- trace propagation through task metadata
- trace messages for processing steps
Example use:
- polling worker creates trace when it discovers a mail
- processing worker resumes trace and writes business steps
### 6. Health
Services:
- `HealthRegistry`
- `WorkerHealth`
What it gives:
- per-worker health
- aggregated application health
- critical vs non-critical component handling
Example use:
- email processing workers are critical
- optional diagnostic worker may be non-critical
### 7. Status
Services:
- `WorkerStatus`
- runtime aggregated state
What it gives:
- current activity visibility
- ability to stop application only after in-flight work is completed
Example use:
- stop application only after processing workers become `idle` or `stopped`
### 8. HTTP control
Services:
- `ControlPlaneService`
- `HttpControlChannel`
What it gives:
- HTTP health/status/actions
- operational integration point
Example use:
- inspect current health from orchestration
- request graceful stop remotely
## Public package API
Public namespace is `plba`.
Main imports for external applications:
```python
from plba import ApplicationModule, QueueWorker, RuntimeManager, create_runtime
from plba.contracts import Task, TaskHandler, TaskQueue, Worker, WorkerHealth, WorkerStatus
from plba.queue import InMemoryTaskQueue
from plba.tracing import TraceService
## 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
```
## Example application pattern
### Архитектурные слои
Minimal queue-based application:
- `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, QueueWorker, Task, TaskHandler, create_runtime
from plba.queue import InMemoryTaskQueue
from plba import ApplicationModule, InMemoryTaskQueue, QueueWorker, RuntimeManager, Task, TaskHandler
class ExampleHandler(TaskHandler):
class PrintHandler(TaskHandler):
def handle(self, task: Task) -> None:
print(task.payload)
class ExampleModule(ApplicationModule):
class DemoModule(ApplicationModule):
@property
def name(self) -> str:
return "example"
return "demo"
def register(self, registry) -> None:
queue = InMemoryTaskQueue()
traces = registry.services.get("traces")
queue.publish(Task(name="incoming", payload={"hello": "world"}))
registry.add_queue("incoming", queue)
registry.add_worker(QueueWorker("example-worker", queue, ExampleHandler(), traces))
handler = PrintHandler()
queue.publish(Task(name="demo-task", payload={"id": 1}, metadata={}))
registry.add_worker(QueueWorker("demo-worker", queue, handler, traces))
runtime = create_runtime(
ExampleModule(),
config_path="config.yml",
enable_http_control=False,
)
runtime = RuntimeManager()
runtime.register_module(DemoModule())
runtime.start()
runtime.stop()
```
## Building business applications on PLBA
These are the current rules for building business applications correctly.
### 1. Keep platform and business concerns separate
PLBA owns:
- lifecycle
- worker management
- logging
- trace infrastructure
- health aggregation
- HTTP control
- config loading
Business application owns:
- business workflows
- domain services
- application-specific config schema
- business task payloads
- business error semantics
### 2. Build app behavior from workers
A business application should be described as a small set of workers.
Typical examples:
- polling worker
- processing worker
- reconciliation worker
Do not introduce new worker types at platform level unless there is clear need for custom runtime behavior.
### 3. Use queues only when they help
Queue is optional.
Use queue when:
- one worker discovers work
- another worker processes it
- buffering or decoupling helps
- concurrency is needed
Do not force queue into applications that do not need it.
### 4. Keep business logic out of worker lifecycle code
Worker should orchestrate execution.
Business rules should live in dedicated services and handlers.
Good:
- worker gets config
- worker calls domain service
- worker reports trace and status
Bad:
- worker contains all parsing, decision logic, integration rules, and persistence rules in one class
### 5. Use trace as a platform service
Business application should:
- create meaningful trace steps
- propagate trace through task metadata if queue is used
- record business-relevant processing milestones
Business application should not:
- implement its own trace store
- control trace transport directly unless explicitly needed
### 6. Read config through PLBA
Business application should not read YAML directly.
Recommended flow:
- PLBA loads config
- application reads only its own config section
- application converts it to typed app config object
- services receive typed config object
### 7. Distinguish health from status
Use `health` for:
- is application operational?
Use `status` for:
- what is application doing right now?
This is important for graceful stop:
- health may still be `ok`
- status may be `busy`
### 8. Design workers for graceful stop
Workers should support:
- stop accepting new work
- finish current in-flight work when possible
- report `busy`, `idle`, `stopping`, `stopped`
This allows runtime to stop application safely.
## Recommended repository model
PLBA is intended to live in its own repository as a reusable package.
Recommended setup:
- repository `plba`: platform package only
- repository `mail_order_bot`: business application depending on `plba`
- repository `service_b`: business application depending on `plba`
## Example: `mail_order_bot`
Simple first version of `mail_order_bot` on PLBA:
- `MailPollingWorker`, concurrency `1`
- `EmailProcessingWorker`, concurrency `3`
- shared `InMemoryTaskQueue`
- domain services for mail parsing and order processing
Flow:
1. polling worker checks IMAP
2. polling worker pushes email tasks into queue
3. processing workers consume tasks
4. processing workers execute domain logic
5. runtime aggregates health and status
This keeps `mail_order_bot` small, explicit, and aligned with current PLBA architecture.