Skip to content

OneStep Control Plane ​

The Control Plane is the centralized ops control surface for the OneStep runtime, providing remote monitoring, telemetry collection, and command dispatch.

Architecture Overview ​

┌──────────────────┐      WebSocket       ┌──────────────────┐      ┌────────────┐
│  OneStep Agent   │ ──────────────────▶   │  Control Plane   │ ──▶  │ PostgreSQL │
│  (ControlPlane   │    onestep-agent.v1   │  API (FastAPI)   │      │            │
│   Reporter)      │ ◀──────────────────   │                  │      │  services  │
└──────────────────┘      commands         │  /api/v1/agents  │      │  instances │
                                           │       /ws        │      │  sessions  │
                                           │                  │      │   tasks    │
                                           │  /api/v1/query   │      │  commands  │
                                           │                  │      │   events   │
                                           │  Console Auth    │      │  metrics   │
                                           └────────┬─────────┘      └────────────┘
                                                    │
                                                    │ SSE / REST
                                                    ▼
                                           ┌──────────────────┐
                                           │   Web Console    │
                                           │  (React + Vite)  │
                                           │                  │
                                           │  Service List    │
                                           │  Task Dashboard  │
                                           │  Instance View   │
                                           │  Command Panel   │
                                           │  Notifications   │
                                           └──────────────────┘

Core concept: OneStep runtime Agents actively connect outbound via WebSocket to the Control Plane (no inbound ports required on the Agent), reporting topology, heartbeats, metrics, and task events, while receiving operational commands.

Core Concepts ​

Service / Instance / Task ​

  • Service: Logical service identifier, uniquely determined by (name, environment)
  • Instance: Runtime instance (UUID identifier), carrying node name, hostname, PID, and version info
  • Task: Task graph definition (Source, Sink, concurrency, timeout, retry policy), tracked for consistency via topology_hash

Topology Description ​

The Reporter's sync telemetry carries task Source/Sink types, names, and config summaries for the control plane to display the task graph and compute topology_hash.

Connectors report by stable type names, e.g., cron, interval, rabbitmq_queue, mysql_table_sink, redis_stream, feishu_bitable_incremental, feishu_bitable_table_sink, and http_sink. Redis Streams reports stream, group, consumer, batch, block, trim, and other topology config; HttpSink reports URL, method, timeout, query parameter names, and success status codes.

Sensitive information is not sent into topology as-is: HttpSink hides URL credentials, removes URL query/fragment, and marks header and params values as <redacted>.

WebSocket Session Lifecycle ​

  1. Agent establishes WebSocket connection, sends hello (protocol version, capability declaration)
  2. Server responds with hello_ack (containing accepted accepted_capabilities)
  3. Agent begins sending telemetry messages (sync / heartbeat / metrics / events)
  4. Server can dispatch command (ping / shutdown / drain / pause_task, etc.)
  5. Agent replies with command_ack (accepted/rejected) and command_result (execution result)

Capability Negotiation ​

The Agent declares its capabilities in hello (e.g., command.ping, command.shutdown, telemetry.sync), and the server only dispatches commands the Agent has accepted.

Command Lifecycle ​

pending → dispatched → accepted/rejected → succeeded/failed/timeout/cancelled

All commands are persisted to the database; unacknowledged commands can be re-dispatched after reconnection.

Since Worker Agent 0.1.5 there is also command result recovery: once an agent advertises the agent.command_recovery capability, every command is persisted to work_dir/commands/ before execution and terminal results are durably recorded before being reported; a repeated command ID returns the existing result directly, and commands for the same deployment execute serially. The control plane re-dispatches accepted commands only to agents with that capability; after an agent restart, an interrupted preparation ends as cancelled, and exit events are retained until the control plane acknowledges receipt.

Online / Offline Detection ​

  • Instance last_seen_at within INSTANCE_OFFLINE_AFTER_S (default 90s) → online
  • Within health participation window INSTANCE_HEALTH_PARTICIPATION_WINDOW_S (default 1h) → counted in service health denominator

Integrating with OneStep Agent ​

Enable Control Plane reporting in your OneStep application:

python
from onestep import (
    ControlPlaneReporter,
    ControlPlaneReporterConfig,
    OneStepApp,
)

app = OneStepApp("my-service")
reporter = ControlPlaneReporter(
    ControlPlaneReporterConfig.from_env(app_name=app.name)
)
reporter.attach(app)

It can also be enabled directly in YAML:

yaml
reporter: true

reporter: true is still the recommended minimal configuration, reading connection info from environment variables. To pin the service description in the config file, use a mapping instead:

yaml
reporter:
  service_description: Synchronizes billing data into the warehouse

Environment variable configuration:

VariableDescriptionExample
ONESTEP_CONTROL_PLANE_URLControl Plane service URLhttp://192.168.1.100:8080
ONESTEP_CONTROL_PLANE_TOKENWorker reporting auth tokenmy-token
ONESTEP_CONTROL_PLANE_ENVIRONMENTDeployment environment labelprod / staging
ONESTEP_SERVICE_NAMEService name; defaults to app.name if not setbilling-sync
ONESTEP_SERVICE_DESCRIPTIONService-level description; shown in service catalog and detail viewsSyncs billing data to warehouse

reporter.service_description / ONESTEP_SERVICE_DESCRIPTION is service-level metadata, independent of task-level descriptions like tasks[].description.

See ControlPlaneReporterConfig.from_env for more configuration options; the complete variable reference is in Environment Variables.

Deploying the Control Plane ​

The Control Plane is a separate repository and deployment unit, providing one-click Docker Compose setup:

bash
git clone https://github.com/mic1on/onestep-control-plane
cd onestep-control-plane
cp .env.example .env
# Edit .env to configure database, Token, etc.
docker compose up --build -d

After startup:

  • Web Console: http://127.0.0.1:4173
  • API: http://127.0.0.1:8000
  • Interactive API Docs: http://127.0.0.1:8000/docs

SQLite local dev mode is also available (no Docker required):

bash
./scripts/start-local.sh

Query API ​

The control plane provides REST query endpoints for the Web Console or third-party integrations:

EndpointDescription
GET /api/v1/servicesService list
GET /api/v1/services/{name}/dashboard?environment=Service dashboard
GET /api/v1/services/{name}/instances?environment=Instance list
GET /api/v1/services/{name}/tasks?environment=Task list
GET /api/v1/services/{name}/tasks/{task}?environment=Task details
GET /api/v1/services/{name}/events?environment=Event stream
GET /api/v1/services/{name}/commands?environment=Command history
GET /api/v1/services/{name}/sessions?environment=Session records
GET /api/v1/events?environment=Cross-service recent event stream

GET /api/v1/services/{name}/events supports the following filter parameters:

ParameterDescription
task_nameFilter by task name
kindFilter by event type (e.g., succeeded / failed / retried / dead_lettered)
instance_idFilter by worker instance
occurred_after / occurred_beforeFilter by time range (UTC ISO time)
limit / offsetPagination

All query endpoints require Console Auth (username/password) authentication.

Notifications & Webhook ​

The Control Plane supports pushing task events to instant messaging tools:

  • Feishu group bot
  • WeChat Work group bot
  • Custom webhooks

Supported event types: task started, succeeded, failed, retried, dead-lettered, missed scheduled start.

Channels are classified along three independent axes: event types, service scope (an empty list = all services, including future ones), and the missed-start grace period. Damping is deliberately asymmetric per event kind: connectivity flips use a stable confirmation window plus flap suppression (rapid up/down oscillations no longer trigger notification storms); task_failed uses burst damping per (channel, service); task_started / task_succeeded / task_missed_start are not damped. Damping state is persisted, so a restart mid-incident cannot reset a counter; a suppressed burst still reports suppressed_failure_count in the summary — silence must never read as health.

POST /channels/{id}/test performs a real webhook request and returns delivered / status code / error message; delivery outcomes are queryable at GET /deliveries — the only feedback loop for "did my alert actually go out?".

Monitoring & Alerting ​

The control plane ships two complementary alert planes:

  • Prometheus rules (Plane A): alert rules live in apps/control-plane/monitoring/prometheus/rules/control-plane.yml with runbooks beside them in apps/control-plane/docs/runbooks/alerts.md (each rule links its runbook: anchor). docker-compose.monitoring.yml runs Prometheus + Alertmanager + blackbox + postgres_exporter in one command; the /metrics endpoint requires a bearer token. A critical alert means the control plane is down, or it has lost the ability to report problems (scan failing, notification delivery failures, metrics missing, scan never ran) — the second class is the more dangerous one: a silent alerting system hides incidents better than a loud outage.
  • Notification subsystem (Plane B): the control plane itself scans and derives events → notification outbox → webhook. Plane B is driven by the control plane, so it is necessarily silent when the control plane is down — which is exactly why Plane A exists.

After touching monitoring configuration, run bash scripts/check-monitoring.sh (also a CI check); it verifies that every metric referenced by a rule is emittable, runbook anchors resolve, and scrape job names line up.

More Resources ​

Released under the MIT License.