Files
attune/work-summary/sensor-service-cleanup-standalone-only.md
2026-02-04 17:46:30 -06:00

162 lines
6.1 KiB
Markdown

# Sensor Service Cleanup: Standalone Sensors Only
**Date**: 2024-02-02
**Status**: Complete
**Breaking Change**: Yes - Removes poll-based sensor support
## Overview
Removed the "builtin" poll-based sensor functionality from the sensor service. The sensor service now exclusively manages standalone sensor processes (like `attune-core-timer-sensor`) that run as independent daemons and communicate via the API.
## Motivation
The original architecture had two sensor modes:
1. **Poll-based sensors**: Scripts executed periodically by the sensor service, which would generate events directly
2. **Standalone sensors**: Independent processes that communicate via API
This created architectural confusion where the sensor service was both:
- Managing sensor process lifecycles ✅
- Directly generating events from sensor output ❌
The correct architecture is that **all sensors are independent processes** that use the API to create events. The sensor service should only manage process lifecycles.
## Changes Made
### Files Deleted
1. **`event_generator.rs`** - Only used for poll-based sensors to directly create events
2. **`rule_matcher.rs`** - Unused module for poll-based rule evaluation
3. **`timer_manager.rs`** - Unused (timer functionality now in `attune-core-timer-sensor` standalone)
4. **`sensor_runtime.rs`** - Only used for executing poll-based sensor scripts
### Files Modified
#### `lib.rs`
- Removed exports for deleted modules
- Cleaner public API surface
#### `service.rs`
- Removed `EventGenerator` dependency
- Updated `SensorManager` initialization to not require event generator
- Removed `event_generator()` accessor method
- Updated documentation
#### `sensor_manager.rs`
**Major architectural simplification:**
- **Removed**: `EventGenerator` dependency
- **Removed**: `SensorRuntime` dependency
- **Removed**: Poll-based sensor support entirely
- **Removed**: `start_poll_based_sensor()` method
- **Removed**: `poll_sensor()` method
- **Removed**: `run_loop()` polling loop
- **Kept**: Standalone sensor support with token provisioning
- **Simplified**: `SensorInstance` now only supports standalone mode
- **Updated**: Documentation to clarify standalone-only architecture
Key architectural changes:
```rust
// Before: Constructor needed event_generator
pub fn new(db: PgPool, event_generator: Arc<EventGenerator>) -> Self
// After: No event generation dependencies
pub fn new(db: PgPool) -> Self
```
The sensor manager now focuses on:
- Starting sensor processes when rules become active
- Stopping sensor processes when no rules need them
- Provisioning authentication tokens for sensor processes
- Monitoring sensor health via process lifecycle
- Logging sensor stdout/stderr
#### API Event Creation Fix
Also fixed a bug in `api/src/routes/events.rs` where the `create_event` endpoint wasn't parsing the `trigger_instance_id` parameter to set rule associations on events. Timer sensors send this parameter in format `"rule_{id}"`, and now the API properly:
1. Parses the rule ID from the string
2. Looks up the rule reference from the database
3. Sets `rule` and `rule_ref` fields on the event record
This ensures timer events (and other rule-specific events) properly show their associated rule in the web UI.
## Architecture After Cleanup
### Sensor Service Responsibilities
1. **Lifecycle Management**: Start/stop sensor processes based on active rules
2. **Token Provisioning**: Create API tokens for sensors to authenticate
3. **Process Monitoring**: Track sensor process health (stdout/stderr logging)
4. **Rule Synchronization**: Listen for rule lifecycle events and adjust sensors
### Sensor Process Responsibilities
1. **Event Generation**: Monitor for conditions and create events via API
2. **Configuration**: Read trigger instance configs and act accordingly
3. **Authentication**: Use provisioned tokens to call API endpoints
4. **Independence**: Run as standalone daemons, no coupling to sensor service
### Example: Timer Sensor
The `attune-core-timer-sensor` standalone process:
- Runs independently as a daemon
- Receives API token and configuration via environment variables
- Monitors database for timer trigger instances
- Creates events by calling `POST /api/v1/events` endpoint
- Passes `trigger_instance_id` to associate events with specific rules
## Testing
- ✅ All sensor service tests pass (17 passed, 3 ignored)
- ✅ Workspace compiles cleanly with no warnings
- ✅ No breaking changes to sensor process interface
## Impact
### For Sensor Developers
**No change** - Sensors were already expected to be standalone processes that call the API
### For Sensor Service
**Simplified** - Removed ~400 lines of poll-based sensor code
**Clearer responsibility** - Only manages process lifecycles, doesn't generate events
**Better separation of concerns** - Event generation is always through the API
### For Event Creation
**Fixed bug** - Rule associations now properly set on timer events
**Web UI** - Events now display their associated rule correctly
## Migration Notes
**No migration needed** - The poll-based sensor functionality was never used in production. All current sensors (e.g., `attune-core-timer-sensor`) are already standalone processes.
## Files Changed
```
Deleted:
- crates/sensor/src/event_generator.rs
- crates/sensor/src/rule_matcher.rs
- crates/sensor/src/timer_manager.rs
- crates/sensor/src/sensor_runtime.rs
Modified:
- crates/sensor/src/lib.rs
- crates/sensor/src/service.rs
- crates/sensor/src/sensor_manager.rs
- crates/api/src/routes/events.rs
```
## Related Documentation
- `docs/architecture/sensor-service.md` - Should be updated to reflect standalone-only architecture
- `docs/architecture/webhook-system-architecture.md` - Webhook sensors follow same pattern
- `packs/core/sensors/interval_timer_sensor.yaml` - Example of standalone sensor config
## Future Considerations
1. **Sensor Discovery**: Consider auto-discovery of sensor binaries in pack directories
2. **Health Checks**: Add more sophisticated sensor health monitoring beyond process lifecycle
3. **Graceful Restart**: Implement graceful sensor restart on configuration changes
4. **Resource Limits**: Add CPU/memory limits for sensor processes