233 lines
6.6 KiB
Markdown
233 lines
6.6 KiB
Markdown
# Timer Sensor Implementation
|
|
|
|
## Overview
|
|
|
|
The timer sensor (`attune-core-timer-sensor`) is a standalone sensor service that monitors all timer-based triggers in Attune and fires events according to their schedules. It uses the [tokio-cron-scheduler](https://crates.io/crates/tokio-cron-scheduler) library for efficient asynchronous scheduling.
|
|
|
|
## Supported Timer Types
|
|
|
|
The timer sensor supports three distinct timer types, each with its own use case:
|
|
|
|
### 1. Interval Timers (`core.intervaltimer`)
|
|
|
|
Fires at regular intervals based on a specified time unit and interval value.
|
|
|
|
**Use Cases:**
|
|
- Periodic health checks
|
|
- Regular data synchronization
|
|
- Scheduled backups
|
|
- Continuous monitoring tasks
|
|
|
|
**Configuration:**
|
|
```yaml
|
|
trigger_ref: core.intervaltimer
|
|
parameters:
|
|
unit: "seconds" # Options: seconds, minutes, hours, days
|
|
interval: 30 # Fire every 30 seconds
|
|
```
|
|
|
|
**Event Payload:**
|
|
```json
|
|
{
|
|
"type": "interval",
|
|
"interval_seconds": 30,
|
|
"fired_at": "2024-01-20T15:30:00Z",
|
|
"execution_count": 42,
|
|
"sensor_ref": "core.interval_timer_sensor"
|
|
}
|
|
```
|
|
|
|
**Examples:**
|
|
- Fire every 10 seconds: `{unit: "seconds", interval: 10}`
|
|
- Fire every 5 minutes: `{unit: "minutes", interval: 5}`
|
|
- Fire every 2 hours: `{unit: "hours", interval: 2}`
|
|
- Fire daily: `{unit: "days", interval: 1}`
|
|
|
|
### 2. Cron Timers (`core.crontimer`)
|
|
|
|
Fires based on cron schedule expressions, providing flexible scheduling with fine-grained control.
|
|
|
|
**Use Cases:**
|
|
- Business hour operations (weekdays 9-5)
|
|
- Scheduled reports (daily at midnight, weekly on Monday)
|
|
- Complex recurring schedules
|
|
- Time-zone-aware scheduling
|
|
|
|
**Configuration:**
|
|
```yaml
|
|
trigger_ref: core.crontimer
|
|
parameters:
|
|
expression: "0 0 9 * * 1-5" # Weekdays at 9 AM
|
|
timezone: "UTC" # Optional, defaults to UTC
|
|
```
|
|
|
|
**Cron Format:**
|
|
```
|
|
second minute hour day_of_month month day_of_week
|
|
| | | | | |
|
|
0-59 0-59 0-23 1-31 1-12 0-6 (0=Sun)
|
|
```
|
|
|
|
**Event Payload:**
|
|
```json
|
|
{
|
|
"type": "cron",
|
|
"fired_at": "2024-01-20T09:00:00Z",
|
|
"scheduled_at": "2024-01-20T09:00:00Z",
|
|
"expression": "0 0 9 * * 1-5",
|
|
"timezone": "UTC",
|
|
"next_fire_at": "2024-01-21T09:00:00Z",
|
|
"execution_count": 15,
|
|
"sensor_ref": "core.interval_timer_sensor"
|
|
}
|
|
```
|
|
|
|
**Examples:**
|
|
- Every hour: `"0 0 * * * *"`
|
|
- Every 15 minutes: `"0 */15 * * * *"`
|
|
- Daily at midnight: `"0 0 0 * * *"`
|
|
- Weekdays at 9 AM: `"0 0 9 * * 1-5"`
|
|
- Every Monday at 8:30 AM: `"0 30 8 * * 1"`
|
|
|
|
### 3. DateTime Timers (`core.datetimetimer`)
|
|
|
|
Fires once at a specific date and time. This is a one-shot timer that automatically removes itself after firing.
|
|
|
|
**Use Cases:**
|
|
- Scheduled deployments
|
|
- One-time notifications
|
|
- Event reminders
|
|
- Deadline triggers
|
|
|
|
**Configuration:**
|
|
```yaml
|
|
trigger_ref: core.datetimetimer
|
|
parameters:
|
|
fire_at: "2024-12-31T23:59:59Z" # ISO 8601 timestamp
|
|
timezone: "UTC" # Optional, defaults to UTC
|
|
```
|
|
|
|
**Event Payload:**
|
|
```json
|
|
{
|
|
"type": "one_shot",
|
|
"fire_at": "2024-12-31T23:59:59Z",
|
|
"fired_at": "2024-12-31T23:59:59.123Z",
|
|
"timezone": "UTC",
|
|
"delay_ms": 123,
|
|
"sensor_ref": "core.interval_timer_sensor"
|
|
}
|
|
```
|
|
|
|
**Examples:**
|
|
- New Year countdown: `{fire_at: "2024-12-31T23:59:59Z"}`
|
|
- Specific deployment time: `{fire_at: "2024-06-15T14:00:00Z", timezone: "America/New_York"}`
|
|
|
|
## Implementation Details
|
|
|
|
### Architecture
|
|
|
|
The timer sensor uses a shared `JobScheduler` from tokio-cron-scheduler to manage all timer types efficiently:
|
|
|
|
1. **Initialization**: Creates a `JobScheduler` instance and starts it
|
|
2. **Job Creation**: Converts each timer config into the appropriate Job type
|
|
3. **Job Management**: Tracks active jobs by rule_id → job_uuid mapping
|
|
4. **Cleanup**: Properly shuts down the scheduler on service termination
|
|
|
|
### Key Components
|
|
|
|
**TimerManager** (`timer_manager.rs`):
|
|
- Central component that manages all timer jobs
|
|
- Methods:
|
|
- `new()`: Creates and starts the scheduler
|
|
- `start_timer()`: Adds/replaces a timer for a rule
|
|
- `stop_timer()`: Removes a specific timer
|
|
- `stop_all()`: Removes all timers
|
|
- `shutdown()`: Gracefully shuts down the scheduler
|
|
|
|
**Job Types**:
|
|
- **Interval**: Uses `Job::new_repeated_async()` with fixed duration
|
|
- **Cron**: Uses `Job::new_async()` with cron expression
|
|
- **DateTime**: Uses `Job::new_one_shot_async()` with duration until fire time
|
|
|
|
### Event Creation
|
|
|
|
All timer types create events via the Attune API using the appropriate trigger ref:
|
|
- Interval → `core.intervaltimer`
|
|
- Cron → `core.crontimer`
|
|
- DateTime → `core.datetimetimer`
|
|
|
|
Each event includes:
|
|
- Trigger-specific metadata (execution count, next fire time, etc.)
|
|
- Timestamp information
|
|
- Sensor reference for tracking
|
|
|
|
### Rule Lifecycle Integration
|
|
|
|
The timer sensor listens to rule lifecycle events via RabbitMQ:
|
|
- **RuleCreated/RuleEnabled**: Starts timer for the rule
|
|
- **RuleDisabled**: Stops timer for the rule
|
|
- **RuleDeleted**: Stops and removes timer for the rule
|
|
|
|
Timer configuration is extracted from rule trigger parameters and converted to the appropriate `TimerConfig` enum variant.
|
|
|
|
## Dependencies
|
|
|
|
```toml
|
|
tokio-cron-scheduler = "0.15" # Core scheduling library
|
|
chrono = "0.4" # Date/time handling
|
|
tokio = { version = "1.41", features = ["full"] }
|
|
```
|
|
|
|
## Testing
|
|
|
|
The implementation includes comprehensive tests covering:
|
|
|
|
1. **Unit Tests**:
|
|
- Timer creation for all types
|
|
- Validation (zero intervals, past dates, invalid cron)
|
|
- Timer start/stop/restart
|
|
- Job replacement
|
|
|
|
2. **Integration Tests**:
|
|
- Multiple concurrent timers
|
|
- Mixed timer type scenarios
|
|
- Cron expression validation
|
|
- Future datetime validation
|
|
|
|
Run tests:
|
|
```bash
|
|
cargo test -p core-timer-sensor
|
|
```
|
|
|
|
## Configuration
|
|
|
|
The timer sensor is configured via environment variables:
|
|
|
|
```bash
|
|
ATTUNE_API_URL=http://localhost:8080
|
|
ATTUNE_API_TOKEN=<service_account_token>
|
|
ATTUNE_SENSOR_REF=core.interval_timer_sensor
|
|
ATTUNE_MQ_URL=amqp://guest:guest@localhost:5672
|
|
ATTUNE_MQ_EXCHANGE=attune
|
|
ATTUNE_LOG_LEVEL=info
|
|
```
|
|
|
|
Or via stdin JSON for containerized environments.
|
|
|
|
## Future Enhancements
|
|
|
|
Possible improvements for the timer sensor:
|
|
|
|
1. **Timezone Support**: Full timezone handling for cron expressions (currently UTC only)
|
|
2. **Persistence**: Store scheduled jobs in database for recovery after restart
|
|
3. **Job History**: Track execution history and statistics
|
|
4. **Advanced Scheduling**: Support for job chaining, dependencies, and priorities
|
|
5. **Performance Metrics**: Expose metrics on job execution timing and success rates
|
|
|
|
## References
|
|
|
|
- [tokio-cron-scheduler Documentation](https://docs.rs/tokio-cron-scheduler/)
|
|
- [Cron Expression Format](https://en.wikipedia.org/wiki/Cron)
|
|
- [ISO 8601 DateTime Format](https://en.wikipedia.org/wiki/ISO_8601)
|