Правки описания
This commit is contained in:
867
README.md
867
README.md
@@ -1,469 +1,444 @@
|
|||||||
# PLBA
|
# PLBA
|
||||||
|
|
||||||
`PLBA` is a reusable platform runtime for business applications.
|
## 1. Общее описание сервиса и его назначение
|
||||||
|
|
||||||
It solves platform concerns that should not live inside domain code:
|
`PLBA` (`Platform Runtime for Business Applications`) - это платформенный runtime для бизнес-приложений. Библиотека выносит из прикладного кода типовые инфраструктурные задачи: жизненный цикл приложения, запуск и остановку фоновых воркеров, загрузку конфигурации, health-check, tracing, логирование и control plane.
|
||||||
- application lifecycle
|
|
||||||
- worker orchestration
|
Назначение сервиса:
|
||||||
- configuration loading from YAML
|
- дать единый каркас для запуска бизнес-модулей;
|
||||||
- tracing
|
- отделить платформенные обязанности от предметной логики;
|
||||||
- health aggregation
|
- упростить разработку сервисов с очередями, polling-обработчиками и фоновыми процессами;
|
||||||
- runtime status reporting
|
- обеспечить наблюдаемость и управляемость runtime через health/status и HTTP control endpoints.
|
||||||
- HTTP control endpoints
|
|
||||||
- logging configuration
|
Текущая модель работы выглядит так:
|
||||||
|
1. приложение создаёт `RuntimeManager`;
|
||||||
Business applications depend on `plba` as a package and implement only their own business behavior.
|
2. runtime загружает конфигурацию;
|
||||||
|
3. применяется logging-конфигурация;
|
||||||
## Architecture
|
4. модуль приложения регистрирует очереди, обработчики, воркеры и health contributors;
|
||||||
|
5. `WorkerSupervisor` запускает все рабочие компоненты;
|
||||||
Current PLBA architecture is built around one core idea:
|
6. runtime агрегирует состояние, health и tracing;
|
||||||
- the runtime manages a set of application workers
|
7. control plane предоставляет снимок состояния и команды запуска/остановки.
|
||||||
|
|
||||||
A worker is any runtime-managed active component with a unified lifecycle:
|
`PLBA` особенно полезен для:
|
||||||
- `start()`
|
- почтовых ботов и интеграционных сервисов;
|
||||||
- `stop(force=False)`
|
- event-driven и queue-driven приложений;
|
||||||
- `health()`
|
- фоновых бизнес-процессов;
|
||||||
- `status()`
|
- внутренних платформенных сервисов с единым operational-контуром.
|
||||||
|
|
||||||
This means PLBA does not require separate platform categories like `source` and `consumer`.
|
## 2. Архитектура - диаграмма классов
|
||||||
If an application needs polling, queue processing, listening, scheduled work, or another active loop, it is implemented as a worker.
|
|
||||||
|
```mermaid
|
||||||
### Main runtime model
|
classDiagram
|
||||||
|
class RuntimeManager {
|
||||||
1. application creates `RuntimeManager`
|
+register_module(module)
|
||||||
2. runtime loads configuration
|
+add_config_file(path)
|
||||||
3. runtime applies logging configuration
|
+start()
|
||||||
4. application module registers workers and supporting services
|
+stop(timeout, force, stop_control_plane)
|
||||||
5. runtime starts all workers
|
+status()
|
||||||
6. workers execute business-related loops or processing
|
+current_health()
|
||||||
7. runtime aggregates health and status
|
}
|
||||||
8. runtime stops workers gracefully or forcefully
|
|
||||||
|
class ConfigurationManager {
|
||||||
## Core concepts
|
+add_provider(provider)
|
||||||
|
+load()
|
||||||
### `ApplicationModule`
|
+reload()
|
||||||
|
+get()
|
||||||
File: [application.py](/Users/alex/Dev_projects_v2/apps/plba/src/app_runtime/contracts/application.py)
|
+section(name, default)
|
||||||
|
}
|
||||||
Describes a business application to the runtime.
|
|
||||||
|
class ServiceContainer {
|
||||||
Responsibilities:
|
+register(name, service)
|
||||||
- provide module name
|
+get(name)
|
||||||
- register workers
|
+require(name, expected_type)
|
||||||
- register queues if needed
|
+snapshot()
|
||||||
- register handlers if needed
|
}
|
||||||
- register health contributors
|
|
||||||
- compose application-specific objects
|
class ModuleRegistry {
|
||||||
|
+register_module(name)
|
||||||
`ApplicationModule` does not run the application itself.
|
+add_queue(name, queue)
|
||||||
It only declares how the application is assembled.
|
+add_handler(name, handler)
|
||||||
|
+add_worker(worker)
|
||||||
### `Worker`
|
+add_health_contributor(contributor)
|
||||||
|
}
|
||||||
File: [worker.py](/Users/alex/Dev_projects_v2/apps/plba/src/app_runtime/contracts/worker.py)
|
|
||||||
|
class ApplicationModule {
|
||||||
The main runtime-managed contract.
|
<<abstract>>
|
||||||
|
+name
|
||||||
Responsibilities:
|
+register(registry)
|
||||||
- start its own execution
|
}
|
||||||
- stop gracefully or forcefully
|
|
||||||
- report health
|
class WorkerSupervisor {
|
||||||
- report runtime status
|
+register(worker)
|
||||||
|
+start()
|
||||||
This is the main extension point for business applications.
|
+stop(timeout, force)
|
||||||
|
+snapshot()
|
||||||
### `TaskQueue`
|
+healths()
|
||||||
|
+statuses()
|
||||||
File: [queue.py](/Users/alex/Dev_projects_v2/apps/plba/src/app_runtime/contracts/queue.py)
|
}
|
||||||
|
|
||||||
Optional queue abstraction.
|
class Worker {
|
||||||
|
<<abstract>>
|
||||||
Use it when application workers need buffered or decoupled processing.
|
+start()
|
||||||
|
+stop(force)
|
||||||
PLBA does not force every application to use a queue.
|
+health()
|
||||||
Queue is one supported pattern, not the foundation of the whole platform.
|
+status()
|
||||||
|
}
|
||||||
### `TaskHandler`
|
|
||||||
|
class QueueWorker {
|
||||||
File: [tasks.py](/Users/alex/Dev_projects_v2/apps/plba/src/app_runtime/contracts/tasks.py)
|
+name
|
||||||
|
+critical
|
||||||
Optional unit of business processing for one task.
|
+start()
|
||||||
|
+stop(force)
|
||||||
Useful when a worker follows queue-driven logic:
|
+health()
|
||||||
- worker takes a task
|
+status()
|
||||||
- handler executes business logic
|
}
|
||||||
|
|
||||||
### `TraceService`
|
class TaskQueue {
|
||||||
|
<<abstract>>
|
||||||
File: [service.py](/Users/alex/Dev_projects_v2/apps/plba/src/app_runtime/tracing/service.py)
|
+publish(task)
|
||||||
|
+consume(timeout)
|
||||||
Platform trace service.
|
+ack(task)
|
||||||
|
+nack(task, retry_delay)
|
||||||
Responsibilities:
|
+stats()
|
||||||
- create trace contexts
|
}
|
||||||
- resume trace from task metadata
|
|
||||||
- write context records
|
class InMemoryTaskQueue {
|
||||||
- write trace messages
|
+publish(task)
|
||||||
|
+consume(timeout)
|
||||||
Business code should use it as a platform service and should not implement its own tracing infrastructure.
|
+ack(task)
|
||||||
|
+nack(task, retry_delay)
|
||||||
### `HealthRegistry`
|
+stats()
|
||||||
|
}
|
||||||
File: [registry.py](/Users/alex/Dev_projects_v2/apps/plba/src/app_runtime/health/registry.py)
|
|
||||||
|
class TaskHandler {
|
||||||
Aggregates application health.
|
<<abstract>>
|
||||||
|
+handle(task)
|
||||||
PLBA uses three health states:
|
}
|
||||||
- `ok` — all critical parts work
|
|
||||||
- `degraded` — application still works, but there is a problem
|
class TraceService {
|
||||||
- `unhealthy` — application should not be considered operational
|
+create_context(...)
|
||||||
|
+open_context(...)
|
||||||
### Runtime status
|
+resume(task_metadata, operation)
|
||||||
|
+attach(task_metadata, context)
|
||||||
File: [types.py](/Users/alex/Dev_projects_v2/apps/plba/src/app_runtime/core/types.py)
|
+info(message, status, attrs)
|
||||||
|
+warning(message, status, attrs)
|
||||||
Status is separate from health.
|
+error(message, status, attrs)
|
||||||
|
}
|
||||||
Current runtime states:
|
|
||||||
- `starting`
|
class HealthRegistry {
|
||||||
- `idle`
|
+register(contributor)
|
||||||
- `busy`
|
+snapshot(worker_healths)
|
||||||
- `stopping`
|
+payload(state, worker_healths)
|
||||||
- `stopped`
|
}
|
||||||
|
|
||||||
Status is used for operational lifecycle decisions such as graceful shutdown.
|
class ControlPlaneService {
|
||||||
|
+register_channel(channel)
|
||||||
### `ControlPlaneService`
|
+start(runtime)
|
||||||
|
+stop()
|
||||||
Files:
|
+snapshot(runtime)
|
||||||
- [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)
|
|
||||||
|
class LogManager {
|
||||||
Provides control and observability endpoints.
|
+apply_config(config)
|
||||||
|
}
|
||||||
Currently supported:
|
|
||||||
- health access
|
class FileConfigProvider {
|
||||||
- runtime start action
|
+load()
|
||||||
- runtime stop action
|
}
|
||||||
- runtime status action
|
|
||||||
|
RuntimeManager --> ConfigurationManager
|
||||||
### `ConfigurationManager`
|
RuntimeManager --> ServiceContainer
|
||||||
|
RuntimeManager --> ModuleRegistry
|
||||||
Files:
|
RuntimeManager --> WorkerSupervisor
|
||||||
- [configuration.py](/Users/alex/Dev_projects_v2/apps/plba/src/app_runtime/core/configuration.py)
|
RuntimeManager --> TraceService
|
||||||
- [file_loader.py](/Users/alex/Dev_projects_v2/apps/plba/src/app_runtime/config/file_loader.py)
|
RuntimeManager --> HealthRegistry
|
||||||
- [providers.py](/Users/alex/Dev_projects_v2/apps/plba/src/app_runtime/config/providers.py)
|
RuntimeManager --> ControlPlaneService
|
||||||
|
RuntimeManager --> LogManager
|
||||||
Loads and merges configuration.
|
RuntimeManager --> ApplicationModule
|
||||||
|
ModuleRegistry --> ServiceContainer
|
||||||
Current built-in source:
|
ModuleRegistry --> Worker
|
||||||
- YAML file provider
|
ModuleRegistry --> TaskQueue
|
||||||
|
ModuleRegistry --> TaskHandler
|
||||||
### `LogManager`
|
WorkerSupervisor --> Worker
|
||||||
|
QueueWorker --|> Worker
|
||||||
File: [manager.py](/Users/alex/Dev_projects_v2/apps/plba/src/app_runtime/logging/manager.py)
|
QueueWorker --> TaskQueue
|
||||||
|
QueueWorker --> TaskHandler
|
||||||
Applies logging configuration from config.
|
QueueWorker --> TraceService
|
||||||
|
InMemoryTaskQueue --|> TaskQueue
|
||||||
Current expectation:
|
ConfigurationManager --> FileConfigProvider
|
||||||
- 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
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 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
|
```python
|
||||||
from plba import ApplicationModule, QueueWorker, Task, TaskHandler, create_runtime
|
from plba import ApplicationModule, InMemoryTaskQueue, QueueWorker, RuntimeManager, Task, TaskHandler
|
||||||
from plba.queue import InMemoryTaskQueue
|
|
||||||
|
|
||||||
|
|
||||||
class ExampleHandler(TaskHandler):
|
class PrintHandler(TaskHandler):
|
||||||
def handle(self, task: Task) -> None:
|
def handle(self, task: Task) -> None:
|
||||||
print(task.payload)
|
print(task.payload)
|
||||||
|
|
||||||
|
|
||||||
class ExampleModule(ApplicationModule):
|
class DemoModule(ApplicationModule):
|
||||||
@property
|
@property
|
||||||
def name(self) -> str:
|
def name(self) -> str:
|
||||||
return "example"
|
return "demo"
|
||||||
|
|
||||||
def register(self, registry) -> None:
|
def register(self, registry) -> None:
|
||||||
queue = InMemoryTaskQueue()
|
queue = InMemoryTaskQueue()
|
||||||
traces = registry.services.get("traces")
|
traces = registry.services.get("traces")
|
||||||
|
handler = PrintHandler()
|
||||||
queue.publish(Task(name="incoming", payload={"hello": "world"}))
|
queue.publish(Task(name="demo-task", payload={"id": 1}, metadata={}))
|
||||||
|
registry.add_worker(QueueWorker("demo-worker", queue, handler, traces))
|
||||||
registry.add_queue("incoming", queue)
|
|
||||||
registry.add_worker(QueueWorker("example-worker", queue, ExampleHandler(), traces))
|
|
||||||
|
|
||||||
|
|
||||||
runtime = create_runtime(
|
runtime = RuntimeManager()
|
||||||
ExampleModule(),
|
runtime.register_module(DemoModule())
|
||||||
config_path="config.yml",
|
|
||||||
enable_http_control=False,
|
|
||||||
)
|
|
||||||
runtime.start()
|
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.
|
|
||||||
|
|||||||
469
requirements/README.md
Normal file
469
requirements/README.md
Normal file
@@ -0,0 +1,469 @@
|
|||||||
|
# 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
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example application pattern
|
||||||
|
|
||||||
|
Minimal queue-based application:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from plba import ApplicationModule, QueueWorker, Task, TaskHandler, create_runtime
|
||||||
|
from plba.queue import InMemoryTaskQueue
|
||||||
|
|
||||||
|
|
||||||
|
class ExampleHandler(TaskHandler):
|
||||||
|
def handle(self, task: Task) -> None:
|
||||||
|
print(task.payload)
|
||||||
|
|
||||||
|
|
||||||
|
class ExampleModule(ApplicationModule):
|
||||||
|
@property
|
||||||
|
def name(self) -> str:
|
||||||
|
return "example"
|
||||||
|
|
||||||
|
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))
|
||||||
|
|
||||||
|
|
||||||
|
runtime = create_runtime(
|
||||||
|
ExampleModule(),
|
||||||
|
config_path="config.yml",
|
||||||
|
enable_http_control=False,
|
||||||
|
)
|
||||||
|
runtime.start()
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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.
|
||||||
Reference in New Issue
Block a user