Skip to main content

Events System

Runix includes a pub/sub event bus with persistent storage for process lifecycle events.

Implementation​

Located at internal/events/:

FileResponsibility
event.goEvent struct and event type constants
bus.goBus — pub/sub with wildcard subscriptions and history
store.goStore — persistent JSON-per-line event log

Event Types​

TypeDescription
process.startedProcess successfully started
process.stoppedProcess stopped cleanly
process.crashedProcess exited with non-zero code
process.healthyHealth check passed (recovered)
process.unhealthyHealth check failed consecutively
process.reloadedProcess was reloaded

Event Structure​

{
"id": "550e8400-e29b-41d4-a716-446655440000",
"type": "process.started",
"timestamp": "2025-01-15T10:30:00Z",
"process_id": "abc123-def456",
"process_name": "api",
"payload": {}
}
FieldTypeDescription
idUUIDUnique event identifier
typestringEvent type
timestampRFC3339UTC timestamp
process_idstringInternal process UUID
process_namestringProcess name
payloadmapOptional additional data

Event Bus​

Publishing​

bus.Emit(events.ProcessStarted, processID, processName, payload)

The bus:

  1. Creates an Event with UUID and UTC timestamp
  2. Appends to the persistent store
  3. Sends to all subscribers for this event type
  4. Sends to wildcard subscribers (subscribed to all types)

Subscribing​

// Subscribe to specific event types
ch := bus.Subscribe(events.ProcessCrashed, events.ProcessUnhealthy)

// Subscribe to all events
ch := bus.Subscribe()

Channels are buffered (capacity 256). If a subscriber's channel is full, events are dropped to prevent blocking the publisher.

Unsubscribing​

bus.Unsubscribe(ch)

Removes the channel from all event type subscriptions.

Persistent Store​

Events are appended to ~/.runix/events.log in JSON-per-line format:

{"id":"...","type":"process.started","timestamp":"...","process_id":"...","process_name":"api","payload":{}}
{"id":"...","type":"process.crashed","timestamp":"...","process_id":"...","process_name":"worker","payload":{"exit_code":1}}

Querying​

// Get events from the last hour
history := bus.History(time.Now().Add(-1 * time.Hour))

// Filter by type
history := bus.History(time.Now().Add(-24*time.Hour), events.ProcessCrashed)

The store reads the file line-by-line and unmarshals each JSON object. Results are filtered by timestamp and optional event types.

CLI Usage​

# View events from last hour
runix events

# Stream live events
runix events --follow

# Filter by type
runix events --type process.crashed

# Custom time range
runix events --since 24h

What's Next​