Satellite Events System
The Satellite Events System provides real-time communication from satellites to the backend for operational visibility, audit trails, and user feedback. Events are processed through a convention-based dispatcher that routes them to handlers updating existing business tables.Architecture Overview
Event Flow
Why Events vs Heartbeat?
DeployStack uses three distinct communication channels: Heartbeat (Every 30 seconds):- Aggregate metrics and system health
- Resource monitoring and capacity planning
- Process counts grouped by team
- Point-in-time occurrences with precise timestamps
- Real-time UI updates and user notifications
- Audit trails for compliance
- Backend-initiated tasks
- Configuration updates and process management
Backend Implementation
Directory Structure
Convention-Based Handler Discovery
The dispatcher automatically discovers and registers handlers from thehandlerModules
array in index.ts
:
- EVENT_TYPE: String constant identifying the event
- SCHEMA: JSON Schema for AJV validation
- handle(): Async function that updates business tables
Handler Interface
All event handlers must implement this interface:Event Processing
Batch Endpoint
Route:POST /api/satellites/{satelliteId}/events
Authentication: Satellite API key (Bearer token via requireSatelliteAuth()
middleware)
Request Schema (uses snake_case for all fields):
Batch Processing Strategy
The dispatcher processes batched events with isolated error handling:- Validate request structure (events array present)
- Validate batch size (1-100 events)
- Process each event individually:
- Check event type exists in registry
- Validate event data against handler schema using AJV
- Parse and validate timestamp
- Call handler.handle() for valid events
- Track successful and failed events
- Return aggregated results
Partial Success Handling
When some events fail validation, the endpoint returns partial success:Implemented Event Types
MCP Server Lifecycle
mcp.server.started
UpdatessatelliteProcesses
table when server successfully spawns.
Business Logic: Sets status=‘running’, records start time and process PID.
Required Fields (snake_case): process_id
, server_id
, server_slug
, team_id
, transport
, tool_count
, spawn_duration_ms
Optional Fields: pid
(OS process ID)
mcp.server.crashed
UpdatessatelliteProcesses
table when server exits unexpectedly.
Business Logic: Sets status=‘failed’, logs error details and exit code.
Required Fields (snake_case): process_id
, server_id
, server_slug
, team_id
, exit_code
, signal
, uptime_seconds
, crash_count
, will_restart
Optional Fields: None (all fields required for proper crash tracking)
Tool Execution
mcp.tool.executed
Inserts record intosatelliteUsageLogs
for analytics and audit trails.
Business Logic: Logs tool execution with metrics, user context, and performance data.
Required Fields (snake_case): tool_name
, server_id
, team_id
, duration_ms
, success
Optional Fields: error_message
(string, only present when success=false)
Creating New Event Handlers
Handler Template
CRITICAL: All event data fields MUST use snake_case naming convention to match satellite event emission and backend API standards. Create a new file inservices/backend/src/events/satellite/
:
Registration Steps
- Create handler file in
services/backend/src/events/satellite/
- Export
EVENT_TYPE
,SCHEMA
, andhandle()
function - Add import to
handlerModules
array inindex.ts
:
- Handler is automatically registered and ready to process events
Schema Validation
AJV Configuration
The dispatcher uses AJV with specific configuration for compatibility:Validation Process
For each event:- Compile handler SCHEMA with AJV
- Validate event.data against compiled schema
- Log validation errors with instance path details
- Skip invalid events (don’t fail entire batch)
Schema Best Practices
- Use
minLength: 1
for required string fields - Include descriptive
description
fields for documentation - Set
additionalProperties: true
to allow future extensibility - Use
required
array for mandatory fields - Leverage AJV formats:
email
,date-time
,uri
,uuid
Database Integration
Event-to-Table Mapping
Events route to existing business tables based on their purpose:Event Type | Business Table | Action |
---|---|---|
mcp.server.started | satelliteProcesses | Update status=‘running’, set start time |
mcp.server.crashed | satelliteProcesses | Update status=‘failed’, log error details |
mcp.tool.executed | satelliteUsageLogs | Insert usage record with metrics |
Transaction Strategy
Each event is processed in a separate database transaction:- Failed events don’t rollback other events
- Maintains data consistency per event
- Isolated error handling prevents cascade failures
Database Driver Compatibility
When updating records, use the driver-compatible pattern:Performance Considerations
Batch Processing Efficiency
- Target: < 100ms per 100-event batch
- Isolation: Each event in separate transaction
- Logging: Structured logging with batch metrics
- Monitoring: Track processing duration and success rates
Database Performance
- Updates use indexed lookups (processId, satelliteId)
- Inserts optimized for high-volume logging
- No generic JSON storage overhead
- Leverages existing optimized table schemas
Memory Usage
- Batch size limited to 100 events (backend validation)
- Event processing is sequential (simple implementation)
- No long-lived memory allocations
- Efficient JSON parsing with TypeScript interfaces
Error Handling
Invalid Event Type
Response: Partial success with failure details Logging: Warn level with event type Action: Skip event, continue batch processingSchema Validation Failure
Response: Partial success with validation errors Logging: Warn level with instance path details Action: Skip event, log validation errorsHandler Execution Error
Response: Partial success with error message Logging: Error level with stack trace Action: Catch error, track failure, continue batchDatabase Transaction Failure
Response: Partial success with database error Logging: Error level with query details Action: Rollback transaction, track failure, continue batchTesting
Unit Testing
Test individual event handlers in isolation:Integration Testing
Test full endpoint with satellite authentication:Batch Processing Tests
- Single event batch (1 event)
- Normal batch (50 events)
- Maximum batch (100 events)
- Oversized batch (> 100 events, should reject)
- Mixed success/failure batch
- Unknown event type handling
- Invalid timestamp handling
- Schema validation failures
Monitoring and Debugging
Structured Logging
All event operations are logged with structured data:Debug Queries
Check registered event types:Best Practices
Event Handler Design
DO:- Update existing business tables with structured data
- Use TypeScript interfaces for type safety
- Include comprehensive field descriptions in schemas
- Log important state changes
- Handle optional fields gracefully
- Store raw JSON in generic events tables
- Assume all optional fields are present
- Skip error handling in database operations
- Use blocking operations (keep handlers async)
- Duplicate business logic across handlers
Schema Design
DO:- Use descriptive field names matching domain concepts
- Include
description
for documentation - Set appropriate
minLength
and format constraints - Use
additionalProperties: true
for extensibility - Mark truly required fields in
required
array
- Over-constrain with excessive validation
- Use generic field names like
data
orinfo
- Forget to set
as const
on schema objects - Validate business logic in schemas (do that in handlers)
- Create schemas with circular references
Database Operations
DO:- Use parameterized queries via Drizzle ORM
- Handle both SQLite and Turso driver differences
- Include timestamps for all state changes
- Use transactions for multi-step operations
- Index frequently queried fields
- Concatenate SQL strings manually
- Assume specific driver properties exist
- Skip error handling for database operations
- Create N+1 query patterns
- Store large BLOBs in event data
Future Enhancements
Planned Event Types
- Client Connections:
mcp.client.connected
,mcp.client.disconnected
- Tool Discovery:
mcp.tools.discovered
,mcp.tools.updated
- Configuration:
config.refreshed
,config.error
- Satellite Lifecycle:
satellite.registered
,satellite.deregistered
- Process Management:
mcp.server.restarted
,mcp.server.permanently_failed
Performance Optimizations
- Batch database insertions for high-volume events
- Async event processing with job queue
- Event sampling for high-frequency events
- Compression for large event payloads
Analytics Features
- Real-time event aggregation
- Custom alert rules based on events
- Event replay for debugging
- Historical event analysis dashboards
Related Documentation
- Satellite Event System - Satellite-side event emission
- Satellite Communication - Full satellite communication architecture
- API Documentation - OpenAPI specification generation
- Database Management - Schema and migrations