diff --git a/README.md b/README.md index a7ad9d1..49ce451 100644 --- a/README.md +++ b/README.md @@ -193,6 +193,51 @@ classDiagram ControlChannelBridge ..> ControlChannel : on_start, on_stop, on_status ``` +## Диаграмма последовательности (запуск и работа) + +```mermaid +sequenceDiagram + autonumber + participant User + participant ConfigManagerV2 + participant ControlChannel as ControlChannel(s) + participant WorkerLoop + participant ConfigLoader + participant Client as HTTP Client + + User->>ConfigManagerV2: start() + ConfigManagerV2->>ConfigManagerV2: _start_control_channels() + ConfigManagerV2->>ControlChannel: start(on_start, on_stop, on_status) + ControlChannel-->>ConfigManagerV2: started + + par Циклы работы + ConfigManagerV2->>WorkerLoop: run() + loop Периодически + WorkerLoop->>ConfigManagerV2: execute() + ConfigManagerV2-->>WorkerLoop: success/error + end + and + loop Периодически + ConfigManagerV2->>ConfigLoader: load_if_changed() + ConfigLoader-->>ConfigManagerV2: config / unchanged + end + end + + Note over Client,ControlChannel: Запросы по HTTP API (если HttpControlChannel) + + Client->>ControlChannel: GET /health + ControlChannel->>ConfigManagerV2: health_provider.collect() + ConfigManagerV2-->>ControlChannel: HealthPayload + ControlChannel-->>Client: 200 OK + + Client->>ControlChannel: POST /actions/stop + ControlChannel->>ConfigManagerV2: on_stop() (bridge) + ConfigManagerV2->>ConfigManagerV2: set halt + ConfigManagerV2->>WorkerLoop: halt_event.set() + ConfigManagerV2->>ControlChannel: stop() + ControlChannel-->>Client: 200 OK +``` + ## Логирование Логирование настраивается из конфигурационного файла только если в нём есть секция **`log`** в формате [dictConfig](https://docs.python.org/3/library/logging.config.html#logging.config.dictConfig). Если секции `log` нет, менеджер пишет предупреждение в лог, а уровень Python по умолчанию (WARNING) сохраняется — сообщения INFO/DEBUG могут не отображаться. @@ -208,51 +253,3 @@ classDiagram - **e-mail**: lesha.spb@gmail.com - **telegram**: https://t.me/lesha_spb ---- - -## Description (English) - -**Config Manager** is a Python package for running applications with periodic execution logic, config reload, and control via HTTP API (and optionally Telegram). - -**Contract:** Your application subclasses **ConfigManagerV2** and overrides **execute()** (periodic work). Control (start/stop, health) is done via channels that are created externally and passed into the constructor as **control_channels** (e.g. **HttpControlChannel** for REST API). - -### Architecture and components - -**ConfigManager** (class **ConfigManagerV2**) is the application entry point. It inherits internal logic from **_RuntimeController** (worker and config-update loops, starting/stopping control channels). - -**Core:** -- **ConfigLoader** — reads config from file (YAML/JSON), computes hash and returns config only when changed; on parse error returns last valid config. -- **WorkerLoop** — in a separate thread, repeatedly calls your **execute()** with a pause; reacts to stop event and success/error callbacks. -- **LogManager** — applies the **log** section from config to logging (dictConfig). -- **HealthAggregator** — aggregates state: lifecycle (idle/starting/running/…), last successful **execute()** time and health timeout; produces a single health response (ok/unhealthy). -- **ControlChannelBridge** — single bridge for all channels: on_start/on_stop/on_status handlers (halt flag and status text). - -**Control channels:** -- **ControlChannel** — abstract contract: **start(on_start, on_stop, on_status)**, **stop()**. -- **HttpControlChannel** — HTTP API (**/health**, **/actions/start**, **/actions/stop**, **/actions/status**); uses **UvicornServerRunner**; **/health** calls **HealthAggregator.collect()**, actions use handlers from **ControlChannelBridge**. -- **TelegramControlChannel** — implementation via Telegram long polling; commands **/start**, **/stop**, **/status** invoke the same handlers. - -**Flow:** On **start()** the manager starts all channels from **control_channels**, then runs two loops: **WorkerLoop** and periodic config refresh via **ConfigLoader**. API control: **/health**, **/actions/start**, **/actions/stop** when **HttpControlChannel** is in **control_channels**. Halt stops both loops; then all channels are stopped. - -### Running with ConfigManagerV2 and HttpControlChannel - -1. Subclass **ConfigManagerV2** and implement **execute()** (your periodic logic). Optionally override **get_health_status()** for custom **/health** response. -2. Create channels externally and pass them to the constructor. For HTTP API create **HttpControlChannel**; for health the manager’s callback is needed — pass **control_channels** as a factory (lambda that receives the manager). -3. Start from an async context: **await app.start()** or **asyncio.create_task(app.start())** for background. Stop: **await app.stop()** or HTTP **/actions/stop**. - -See the minimal example in the Russian section above; a full example is in **tests/test_app.py**. - -### Logging - -Logging is configured from the config file only if it contains a **log** section in [dictConfig](https://docs.python.org/3/library/logging.config.html#logging.config.dictConfig) format. If **log** is missing, the manager logs a warning and the default Python level (WARNING) remains. - -### Installation - -```bash -pip install git+https://git.lesha.spb.ru/alex/config_manager.git -``` - -### Contacts - -- **e-mail**: lesha.spb@gmail.com -- **telegram**: https://t.me/lesha_spb