-
Notifications
You must be signed in to change notification settings - Fork 0
Event Bus and Webhooks
Relevant source files
The following files were used as context for generating this wiki page:
The internal/events package provides an asynchronous, in-process event bus designed for observability and cluster-wide coordination internal/events/events.go:1-3. It serves as the central nervous system for AXIS, emitting lifecycle events for task placement, resource reservations, and daemon state changes. These events can be consumed by local listeners, propagated across the cluster via Cortex, or dispatched to external systems through webhooks internal/events/events.go:22-27, internal/events/webhooks.go:39-40.
AXIS defines a set of standard event names that represent the state transitions of various subsystems.
| Category | Constant | String Value | Description |
|---|---|---|---|
| Task | EventTaskPlacementRequested |
task.placement.requested |
Emitted before a placement decision is made internal/events/events.go:35-37. |
EventTaskExecutionPre |
task.execution.pre |
Emitted immediately before a task starts internal/events/events.go:39-40. | |
EventTaskExecutionReserved |
task.execution.reserved |
Emitted after RAM/VRAM is committed in the ledger internal/events/events.go:42-43. | |
EventTaskExecutionPost |
task.execution.post |
Emitted after task completion (success/failure) internal/events/events.go:48-49. | |
| Reservation | EventReservationRequested |
reservation.requested |
Emitted when an advisory lease is requested internal/events/events.go:57-58. |
EventReservationGranted |
reservation.granted |
Emitted when a reservation is recorded internal/events/events.go:60-61. | |
| Daemon | EventDaemonRefreshPost |
daemon.refresh.post |
Emitted after a snapshot refresh completes internal/events/events.go:72-73. |
Sources: internal/events/events.go:30-77
The event system uses a multi-tiered approach for persistence and propagation:
- In-Process Listeners: Synchronous registration but asynchronous execution via goroutines internal/events/events.go:162-169.
-
Cortex Propagation: If a
cortex.Clientis registered viaSetCortexClient, events are wrapped in aPublishEnvelopeand broadcast cluster-wide internal/events/events.go:22-27, internal/events/events.go:94-98. -
JSONL Logging: Events are persisted to
~/.axis/events.jsonlusing a monotonic sequence number allocated via a file-lock (flock) mechanism to ensure consistency across multiple processes internal/events/logger.go:37-57, internal/events/logger.go:92-106.
The following diagram illustrates how an event emitted by a subsystem (e.g., the Execution Engine) moves through the system.
graph TD
subgraph "Event Source"
A["Subsystem (e.g. RunGuarded)"] -- "Emit()" --> B["internal/events.EmitToBuffer"]
end
subgraph "In-Process Dispatch"
B --> C["listenerMu (sync.Mutex)"]
C --> D["notifyListeners()"]
D --> E["Goroutine per Listener"]
end
subgraph "External & Cluster Propagation"
B --> F["cortexClient.PublishEvent"]
B --> G["dispatchWebhooks()"]
end
subgraph "Persistence"
B --> H["allocateSequence() (flock)"]
H --> I["appendEventToFile()"]
I --> J["~/.axis/events.jsonl"]
end
style J stroke-dasharray: 5 5
Sources: internal/events/events.go:124-170, internal/events/logger.go:37-57, internal/events/webhooks.go:40-44
The webhook system allows AXIS to notify external HTTP endpoints of lifecycle events.
- Async Dispatch: Webhooks are posted asynchronously to avoid blocking the main event bus internal/events/webhooks.go:39-40.
-
Retry Logic: The
postWithRetryfunction implements an exponential backoff (starting at 1s) and attempts up to 4 deliveries (1 initial + 3 retries) internal/events/webhooks.go:64-91. -
Dead-Letter Office: If all retries fail, the event and the error details are written to
~/.axis/webhook-deadletter.jsonlfor manual auditing internal/events/webhooks.go:105-135.
Sources: internal/events/webhooks.go:1-137, internal/events/webhooks_test.go:66-89
The internal/events package maintains an interests registry specifically for Model Context Protocol (MCP) clients internal/events/events.go:203-211. This allows external AI agents to subscribe to specific event types.
-
RegisterInterest(eventName, subscriber): Records that a specific MCP client is interested in an event name internal/events/events.go:211-215. -
Reference Client: The
examples/mcp-event-clientdemonstrates how an agent can use MCP tools likelist_lifecycle_eventsandget_recent_eventsto observe cluster behavior examples/mcp-event-client/main.go:37-62.
This diagram maps the MCP Tool names used by AI agents to the internal functions in the events package.
graph LR
subgraph "MCP Client (examples/mcp-event-client)"
M1["CallTool('list_lifecycle_events')"]
M2["CallTool('register_event_interest')"]
M3["CallTool('get_recent_events')"]
end
subgraph "internal/events Package"
E1["Event Name Constants"]
E2["RegisterInterest()"]
E3["GetRecentEvents()"]
E4["getRecentEventsFromFile()"]
end
M1 --> E1
M2 --> E2
M3 --> E3
E3 --> E4
Sources: internal/events/events.go:211-227, internal/events/logger.go:170-219, examples/mcp-event-client/main.go:37-62
AXIS maintains a rolling window of events on disk to prevent unbounded storage growth.
-
Rotation: When
events.jsonlexceeds 10MB, it is rotated. AXIS keeps up to 9 historical log files (events.1.jsonlthroughevents.9.jsonl) internal/events/logger.go:121-125, internal/events/logger.go:153-166. -
Sequence Consistency: The
allocateSequencefunction usessyscall.Flockonevent-sequence.lockto ensure that even if multiple AXIS processes (CLI and Daemon) emit events simultaneously, the sequence numbers remain strictly monotonic and unique internal/events/logger.go:37-57.
Sources: internal/events/logger.go:37-89, internal/events/logger.go:121-167