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.progress
andactions.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.progress
andactions.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
.