PLBA
1. Назначение платформы
PLBA (Platform Runtime for Business Applications) - это runtime-слой для бизнес-приложений, который забирает на себя инфраструктурную часть исполнения. Платформа стандартизирует запуск и остановку рабочих процессов, контроль состояния приложения и эксплуатационные сервисы вокруг них. За счет этого прикладной код концентрируется на бизнес-логике, а не на lifecycle, диагностике и служебных механизмах. Базовая модель использования строится вокруг ApplicationModule, Worker и прикладной Routine, где каждый уровень отвечает за свою часть ответственности. В результате приложение получается предсказуемым в эксплуатации, проще в сопровождении и масштабировании.
2. Концепция использования
ApplicationModule - точка сборки приложения: здесь создаются зависимости, собираются рутины, создаются воркеры и регистрируются дополнительные health-контрибьюторы.
Worker - основной runtime-контракт платформы: он управляет исполнением (потоки, цикл, стратегия остановки), возвращает health() и status(), а также определяет критичность компонента для общего health.
Routine - прикладной паттерн (не обязательный контракт платформы): класс или набор классов, где сосредоточена бизнес-логика, которую воркер регулярно или однократно запускает.
Вспомогательные сервисы платформы дополняют core-модель:
tracing(TraceService, транспорты) - операционная трассировка контекстов и сообщений.logging(LogManager) - применение конфигурации логирования из runtime-конфига.health(HealthRegistry) - агрегирование здоровья воркеров и дополнительных компонентов.workflow(WorkflowEngineи persistence-слой) - исполнение шагов бизнес-процесса с переходами и фиксацией состояния.control plane(ControlPlaneService,HttpControlChannel) - внешние health/action endpoints.queue(InMemoryTaskQueue) - локальный in-memory буфер как утилита прикладного уровня.
3. Архитектура
classDiagram
class ApplicationModule {
<<abstract>>
+name: str
+register(registry)
}
class ModuleRegistry {
+add_worker(worker)
+add_health_contributor(contributor)
+register_module(name)
}
class RuntimeManager {
+register_module(module)
+add_config_file(path)
+start()
+stop(timeout, force)
+status()
+current_health()
}
class WorkerSupervisor {
+register(worker)
+start()
+stop(timeout, force)
+statuses()
+healths()
}
class Worker {
<<abstract>>
+name: str
+critical: bool
+start()
+stop(force)
+health()
+status()
}
class Routine {
<<pattern>>
+run()
}
class ConfigurationManager
class LogManager
class HealthRegistry
class TraceService
class ControlPlaneService
class WorkflowRuntimeFactory
class WorkflowEngine
class WorkflowPersistence
class WorkflowRepository
class CheckpointRepository
class InMemoryTaskQueue
class MySqlTraceTransport
ApplicationModule --> ModuleRegistry : register(...)
RuntimeManager --> ApplicationModule : register_module(...)
RuntimeManager --> ModuleRegistry
RuntimeManager --> ConfigurationManager
RuntimeManager --> LogManager
RuntimeManager --> HealthRegistry
RuntimeManager --> TraceService
RuntimeManager --> WorkerSupervisor
RuntimeManager --> ControlPlaneService
WorkerSupervisor --> Worker
Worker --> Routine : invokes
WorkflowRuntimeFactory --> WorkflowEngine : create_engine(...)
WorkflowEngine --> WorkflowPersistence
WorkflowPersistence --> WorkflowRepository
WorkflowPersistence --> CheckpointRepository
TraceService --> MySqlTraceTransport
4. Описание компонентов
4.1 Core модули
ApplicationModule
- Назначение: композиция прикладного приложения и регистрация runtime-компонентов.
- Реализация: контракт
app_runtime.contracts.application.ApplicationModule, регистрация черезapp_runtime.core.registration.ModuleRegistry. - Как работает / API / вызовы / таблицы:
- API:
name,register(registry). - Типичные вызовы:
registry.add_worker(worker),registry.add_health_contributor(contributor). RuntimeManager.register_module()вызываетmodule.register(...)и добавляет имя модуля в снимок runtime.- В БД напрямую не пишет.
- API:
- Типовая схема использования:
- Создать инфраструктурные и доменные сервисы.
- Создать
Routine. - Создать
Workerс зависимостью на рутину. - Зарегистрировать воркер и опциональные health contributors.
Worker
- Назначение: runtime-исполнение бизнес-активности, управление lifecycle, интерпретация health/status.
- Реализация: контракт
app_runtime.contracts.worker.Worker, оркестрация черезapp_runtime.workers.supervisor.WorkerSupervisor. - Как работает / API / вызовы / таблицы:
- API:
start(),stop(force=False),health() -> WorkerHealth,status() -> WorkerStatus, свойстваname,critical. WorkerSupervisor.start()запускает все воркеры,stop()останавливает и ждет state=stopped.RuntimeManagerполучает агрегированныеstatuses()/healths()у супервизора.- В БД напрямую не пишет (если прикладной worker сам не реализует persistence).
- API:
- Типовая схема использования:
- Внутри
start()поднимать поток/пул или запускать одноразовую задачу. - В цикле вызывать
routine.run(). - Ошибки бизнес-логики транслировать в
health()/status().
- Внутри
Routine
- Назначение: изоляция прикладной бизнес-логики от runtime-обвязки.
- Реализация: прикладной класс (паттерн), обычно с методом
run(); платформой не навязывается отдельный интерфейс. - Как работает / API / вызовы / таблицы:
- Типичный API:
run()+ дополнительные domain-методы. - Вызывается воркером в выбранной стратегии выполнения (single-run/loop, 1..N потоков).
- Может вызывать сервисы интеграций, workflow, очереди, доменные репозитории.
- Запись в таблицы определяется прикладными сервисами, а не самой платформой.
- Типичный API:
- Типовая схема использования:
- Оставлять рутину тонким оркестратором бизнес-действий.
- Сложную логику выносить в отдельные доменные сервисы.
4.2 Service модули
Configuration
- Назначение: централизованная загрузка и слияние runtime-конфигурации.
- Реализация:
ConfigurationManager,FileConfigProvider,ConfigFileLoader. - Как работает / API / вызовы / таблицы:
- API:
add_provider(),load(),reload(),get(),section(). RuntimeManager.start()вызываетconfiguration.load().- Поддерживается YAML/JSON через
ConfigFileLoader.parse(). - В БД не пишет.
- API:
- Типовая схема использования:
- В bootstrap добавить файл:
runtime.add_config_file("config.yml"). - Читать секции из
runtime.configuration.section("...")в прикладных фабриках.
- В bootstrap добавить файл:
Logging
- Назначение: применение и восстановление валидной конфигурации логирования.
- Реализация:
LogManager. - Как работает / API / вызовы / таблицы:
- API:
apply_config(config). RuntimeManager.start()вызываетlogs.apply_config(config).- Если секция
logнекорректна, сервис пытается восстановить предыдущую валидную конфигурацию. - В БД не пишет.
- API:
- Типовая схема использования:
- Передать
logсекцию в конфиг и запускать runtime стандартно черезstart().
- Передать
Health
- Назначение: сводный health приложения по воркерам и дополнительным контрибьюторам.
- Реализация:
HealthRegistry+ контрибьюторы по контрактуHealthContributor. - Как работает / API / вызовы / таблицы:
- API:
register(),snapshot(worker_healths),payload(state, worker_healths). - Агрегация:
unhealthyпри критичномunhealthy,degradedпри любой деградации, иначеok. RuntimeManager.current_health()используетHealthRegistry.payload(...).- В БД не пишет.
- API:
- Типовая схема использования:
- Зарегистрировать contributor в
ApplicationModule.register(...). - Отдавать health наружу через control plane
/health.
- Зарегистрировать contributor в
Tracing
- Назначение: фиксация контекстов выполнения и событий по шагам операций.
- Реализация:
TraceService,TraceContextStore,NoOpTraceTransport,MySqlTraceTransport. - Как работает / API / вызовы / таблицы:
- API:
create_context(),open_context(),step(),info()/warning()/error()/exception(),new_root(),child_of(),attach(),resume(). TraceServiceпишет записи через transport; ошибки транспорта изолируются в логах.- При
MySqlTraceTransportзаписи идут в таблицы:trace_contextstrace_messages
- Эталонная схема и migration для MySQL:
requirements/sql/trace_mysql_schema.sql.
- API:
- Trace Context:
- Что это: запись о начале логического контекста выполнения (операция, воркер, подоперация), к которой потом привязываются trace-сообщения.
- Для чего нужен: позволяет собрать дерево исполнения и связать все сообщения конкретной бизнес-операции.
- Атрибуты контекста (
TraceContextRecord):trace_id,alias,parent_id,type,event_time,attrs. - Иерархия:
parent_idуказывает на родительский контекст; так строится цепочка root -> child. - Таблица:
trace_contexts. - Как объявляется в коде:
with traces.open_context(alias="orders-worker", kind="worker", attrs={"routine": "orders"}) as trace_id:
...
root = traces.new_root("orders.sync")
child = traces.child_of(root, "orders.process_batch")
- Trace Message:
- Что это: событие внутри активного context (статус шага, предупреждение, ошибка, служебная информация).
- Роль
step: текущая стадия операции (parse,validate,persistи т.д.), которую выставляют черезtraces.step("..."). - Уровни сообщений:
INFO,WARNING,ERROR;exception(...)пишет сообщение уровняERROR. - Атрибуты сообщения (
TraceLogMessage):trace_id,step,status,message,level,event_time,attrs. - Связь с context: каждое сообщение обязательно связано с текущим активным
trace_id; без активного контекстаTraceServiceвыбрасывает ошибку. - Таблица:
trace_messages. - Как правильно применять в проекте:
- Открывать один root-context на единицу бизнес-работы (например, обработка одного сообщения/заказа).
- Перед важными этапами явно менять
step. infoиспользовать для нормального прогресса,warningдля recoverable ситуаций (retry/fallback),error/exceptionдля сбоев.- В
attrsкласть диагностические ключи (entity_id,attempt,integration,duration_ms), чтобы ускорить расследование инцидентов.
- Типовая схема использования:
- В воркере открыть контекст (
open_context) и на каждом шаге рутины писатьstep()/info().
- В воркере открыть контекст (
Workflow
- Назначение: исполнение step-based workflow с переходами и сохранением прогресса.
- Реализация:
WorkflowRuntimeFactory,WorkflowEngine,WorkflowPersistence,WorkflowRepository,CheckpointRepository. - Как работает / API / вызовы / таблицы:
- API верхнего уровня:
WorkflowRuntimeFactory.create_engine(workflow),WorkflowEngine.run(context). WorkflowEngineпо шагам вызываетWorkflowStep.run(context), применяетTransitionResolver, вызывает hooks.WorkflowPersistenceпишет состояние run/step/checkpoint через репозитории.- При настроенном подключении к БД записи идут в таблицы:
workflow_runsworkflow_stepsworkflow_checkpoints
- Без подключения работает in-memory fallback репозиториев.
- API верхнего уровня:
- Типовая схема использования:
- Описать
WorkflowDefinition(узлы и transitions). - Создать engine через фабрику.
- Запускать из рутины или воркера:
engine.run(context).
- Описать
Control Plane
- Назначение: внешний канал управления runtime и чтения health/status.
- Реализация:
ControlPlaneService,HttpControlChannel,HttpControlAppFactory. - Как работает / API / вызовы / таблицы:
- API:
register_channel(),start(runtime),stop(),snapshot(runtime). - HTTP-канал поднимает endpoint'ы:
GET /healthGET|POST /actions/{action}(start,stop,status)
- Колбэки action'ов вызывают async-методы
RuntimeManager. - В БД не пишет.
- API:
- Типовая схема использования:
- При создании runtime включить
enable_http_control=True. - Использовать
/healthдля readiness/liveness и/actions/*для операционного контроля.
- При создании runtime включить
Queue
- Назначение: простой in-memory буфер задач/сообщений внутри приложения.
- Реализация:
InMemoryTaskQueue[T]. - Как работает / API / вызовы / таблицы:
- API:
put(item),get(timeout),task_done(),qsize(),stats(). - Может использоваться между воркерами/сервисами как локальная очередь.
- В БД не пишет.
- API:
- Типовая схема использования:
- Producer в рутине кладет элементы через
put. - Consumer-воркер извлекает через
get(timeout)и обрабатывает.
- Producer в рутине кладет элементы через
5. MVP бизнес-приложения
Минимальная конфигурация запуска:
- Создать один
ApplicationModule. - В модуле собрать одну
Routineи одинWorker(1 worker -> 1 routine). - Зарегистрировать воркер через
registry.add_worker(...). - Создать runtime:
create_runtime(module, config_path="config.yml"). - Вызвать
runtime.start().
Минимальный пример:
from plba import ApplicationModule, Worker, WorkerHealth, WorkerStatus, create_runtime
from app_runtime.core.registration import ModuleRegistry
class DemoRoutine:
def run(self) -> None:
print("business action")
class DemoWorker(Worker):
def __init__(self, routine: DemoRoutine) -> None:
self._routine = routine
self._started = False
@property
def name(self) -> str:
return "demo-worker"
@property
def critical(self) -> bool:
return True
def start(self) -> None:
self._started = True
self._routine.run()
def stop(self, force: bool = False) -> None:
del force
self._started = False
def health(self) -> WorkerHealth:
return WorkerHealth(name=self.name, status="ok", critical=self.critical)
def status(self) -> WorkerStatus:
return WorkerStatus(name=self.name, state="idle" if self._started else "stopped")
class DemoModule(ApplicationModule):
@property
def name(self) -> str:
return "demo"
def register(self, registry: ModuleRegistry) -> None:
registry.add_worker(DemoWorker(DemoRoutine()))
runtime = create_runtime(DemoModule(), config_path="config.yml")
runtime.start()
Для production-сценария после MVP обычно добавляют tracing, health contributors, workflow и HTTP control plane, но базовый запуск не требует этих расширений.