Actions Are Just Events
Karma treats decisions and commands the same way it treats observations — as events.
Instead of calling a system directly, Karma writes an action request to Kafka.
Subscribers (executors) perform the work and report progress and results back as more events.
Core Topics
events.normalized— raw observations from any CDC-like source.actions.requested— commands Karma issues.actions.progress— in-flight status (started, retrying, percent).actions.result— outcomes (succeeded / failed / cancelled).actions.dlq— unprocessable or exhausted retries.
Action Lifecycle
REQUESTED → ACCEPTED → STARTED → (RETRYING)* → {SUCCEEDED | FAILED | CANCELLED}
Each state change is its own event, correlated by action_id.
Action Envelope
Actions use the same envelope as normalized events, with a command payload:
{
"ts": "2025-08-10T16:42:00Z",
"event_type": "action.requested",
"entity_id": "job:abc123",
"correlation_id": "slot:2025-08-10T16:30Z",
"idempotency_key": "act:restart:job:abc123:1691685720",
"source": {"system":"karma","ns":{"component":"rules-fsm"}},
"tags": {"action":"restart_job","priority":"high","tenant":"foo"},
"attrs": {
"command": "restart_job",
"args": {"job_id":"abc123","force":true},
"ttl_sec": 600
}
}
Workers publish progress and outcomes with the same action_id:
{ "event_type":"action.started", ... }
{ "event_type":"action.succeeded", "attrs":{"duration_ms": 3820} }
{ "event_type":"action.failed", "attrs":{"error":"timeout"} }
Why Model Actions as Events?
- Auditability — every decision, attempt, and result is in the ledger.
- Loose Coupling — rules don’t care who executes the action.
- Retry & Recovery — retries, compensations, and DLQs are first-class.
- Unified Analytics — MTTA, MTTR, success rate, error taxonomy, all in ClickHouse.
- Same Pipeline — actions and observations share infrastructure.
Execution Model
- Producers: Lambdas, FSMs, or ML models decide what to do and publish to
actions.requested. - Consumers: Executors for each domain (Control-M, Slack, S3, APIs) consume and perform the work.
- Results: Executors publish to
actions.progressandactions.result, which flow back into the ledger.
Synchronous APIs (Optional)
Even “sync” calls are just wrappers:
- API publishes to
actions.requested. - Returns an
action_id. - UI polls or subscribes for updates from
actions.progressandactions.result.
Observability
In ClickHouse, build materialized views:
action_state_current— latest status per action.- MTTA / MTTR by action type or tenant.
- Success rates and error categories.
- Link actions to the triggering event via
correlation_id.