10 KiB
Work Summary: Unified Runtime Detection System
Date: 2024-02-03
Status: ✅ Complete
Related Documentation:
docs/sensors/database-driven-runtime-detection.mddocs/sensors/sensor-worker-registration.md
Overview
Consolidated runtime detection logic from sensor and worker services into a unified system in the attune-common crate. Removed the redundant runtime_type distinction between action and sensor runtimes, as both use identical binaries and verification processes.
Key Changes
1. Removed runtime_type Field from Database Schema
Migration: migrations/20260203000001_unify_runtimes.sql
- Dropped
runtime_typeenum column fromruntimetable - Dropped
runtime_type_enumPostgreSQL enum type - Consolidated duplicate runtime records:
core.action.python+core.sensor.python→core.pythoncore.action.nodejs+core.sensor.nodejs→core.nodejscore.action.shell+core.sensor.shell→core.shellcore.action.native+core.sensor.native→core.native
- Migrated all foreign key references in
actionandsensortables - Updated indexes to remove
runtime_typereferences - Kept
core.sensor.builtinas sensor-specific (for internal timers/triggers)
2. Created Unified Runtime Detection Module
New File: crates/common/src/runtime_detection.rs
Provides a single RuntimeDetector service used by both worker and sensor services:
pub struct RuntimeDetector {
pool: PgPool,
}
impl RuntimeDetector {
pub async fn detect_capabilities(
&self,
config: &Config,
env_var_name: &str,
config_capabilities: Option<&HashMap<String, serde_json::Value>>,
) -> Result<HashMap<String, serde_json::Value>>
}
Features:
- Three-tier priority configuration:
- Environment variable override (e.g.,
ATTUNE_WORKER_RUNTIMES,ATTUNE_SENSOR_RUNTIMES) - Config file specification
- Database-driven detection with verification
- Environment variable override (e.g.,
- Queries unified
runtimetable (noruntime_typefilter needed) - Uses verification metadata from database to check runtime availability
- Supports verification commands, exit codes, regex patterns, and "always available" flags
- Returns detected capabilities as HashMap for worker registration
3. Updated Runtime Model
File: crates/common/src/models.rs
- Removed
runtime_typefield fromRuntimestruct - Removed
RuntimeTypeenum fromenumsmodule - Updated all SQLx
FromRowderives to exclude the field
4. Updated Runtime Repository
File: crates/common/src/repositories/runtime.rs
- Removed
runtime_typefromCreateRuntimeInput - Updated all SQL queries to exclude
runtime_typecolumn - Removed
find_by_type()method (no longer needed) - Updated
find_by_pack()to work without type filtering
5. Refactored Worker Service
File: crates/worker/src/registration.rs
Before:
- Hardcoded
auto_detect_runtimes()function - Checked for binaries using
Command::new("python3").arg("--version") - No database integration
After:
- Uses
RuntimeDetector::detect_capabilities()from common crate - Calls detection in
detect_capabilities()async method - Worker service calls this before registration in
start()method - Removed hardcoded detection logic
6. Refactored Sensor Service
File: crates/sensor/src/sensor_worker_registration.rs
Before:
- Inline runtime detection with
verify_runtime_available()andtry_verification_command() - Duplicated verification logic from what would be needed in worker
After:
- Uses
RuntimeDetector::detect_capabilities()from common crate - Removed 200+ lines of duplicate verification code
- Simplified to just call shared detector
- Updated
register()signature to accept&Configparameter
File: crates/sensor/src/service.rs
- Changed
_configtoconfig(stored, not discarded) - Passes config to registration during
start()
7. Updated Test Infrastructure
Files:
crates/common/tests/helpers.rs- RemovedRuntimeTypefromRuntimeFixturecrates/common/tests/repository_runtime_tests.rs- Updated all tests to removeruntime_typeparameter
Changes:
RuntimeFixture::new()signature: removedruntime_typeparameter- Updated runtime ref format from
core.action.pythontocore.python - Fixed 15+ test functions to work without runtime type
Rationale: Why Unify Runtimes?
Problem with Separate Runtime Types
- Duplicate Records: Same binary (e.g.,
python3) had separate database records for actions and sensors - Duplicate Logic: Worker and sensor services had identical verification code
- Maintenance Burden: Changes to runtime detection required updates in 2+ places
- Conceptual Mismatch: Runtime type (
actionvssensor) describes usage, not capability
Benefits of Unified System
- Single Source of Truth: One database record per actual runtime binary
- Code Reuse: Shared detection logic in common crate
- Easier Extension: Adding new runtimes (Ruby, Go, etc.) requires only database records
- Clearer Semantics: Runtime describes what it is (Python, Node.js), not what uses it
Example: Before vs After
Before:
-- Two separate records for the same Python binary
INSERT INTO runtime (ref, runtime_type, name) VALUES ('core.action.python', 'action', 'Python');
INSERT INTO runtime (ref, runtime_type, name) VALUES ('core.sensor.python', 'sensor', 'Python');
After:
-- One unified record
INSERT INTO runtime (ref, name) VALUES ('core.python', 'Python');
-- Used by both actions and sensors
Configuration Examples
Environment Variable Override
# Worker runtimes
export ATTUNE_WORKER_RUNTIMES="python,shell,node"
# Sensor runtimes
export ATTUNE_SENSOR_RUNTIMES="python,shell,builtin"
Config File
worker:
capabilities:
runtimes: ["python", "shell", "node"]
sensor:
capabilities:
runtimes: ["python", "shell", "builtin"]
Database-Driven (Default)
If no env var or config, services query runtime table and verify each:
- Check
distributions->verification->always_available - Or execute verification commands and check exit codes/patterns
- Report only available runtimes in worker capabilities
Migration Path
For Existing Deployments
-
Run Migration:
migrations/20260203000001_unify_runtimes.sql- Automatically consolidates runtime records
- Migrates all foreign key references
- No manual intervention required
-
Restart Services: Worker and sensor services pick up changes automatically
-
Verify: Check worker capabilities in database:
SELECT name, capabilities->'runtimes' FROM worker;
For New Deployments
- Migration runs as part of standard setup
- Core pack loads unified runtimes (
core.python,core.shell, etc.) - Services auto-detect capabilities on first start
Testing
Compilation
cargo check --workspace
# ✅ All services compile successfully
Unit Tests
cargo test -p attune-common runtime
# ✅ All runtime repository tests pass
Integration Tests
cargo test --test repository_runtime_tests
# ✅ CRUD operations work without runtime_type
Files Changed
New Files
migrations/20260203000001_unify_runtimes.sql(338 lines)crates/common/src/runtime_detection.rs(338 lines)
Modified Files
crates/common/src/lib.rs- Added runtime_detection module exportcrates/common/src/models.rs- Removed RuntimeType enum and fieldcrates/common/src/repositories/runtime.rs- Removed runtime_type column referencescrates/common/Cargo.toml- Added regex dependencycrates/worker/src/registration.rs- Replaced auto-detection with RuntimeDetectorcrates/worker/src/service.rs- Call detect_capabilities before registrationcrates/sensor/src/sensor_worker_registration.rs- Replaced inline detection with RuntimeDetectorcrates/sensor/src/service.rs- Store config and pass to registrationcrates/common/tests/helpers.rs- Updated RuntimeFixturecrates/common/tests/repository_runtime_tests.rs- Removed runtime_type from tests
Lines Changed
- Added: ~676 lines (migration + runtime_detection module)
- Removed: ~550 lines (duplicate detection code, enum, test updates)
- Net: +126 lines (mostly migration documentation)
Breaking Changes
Database Schema
runtime_typecolumn removed fromruntimetableruntime_type_enumPostgreSQL type dropped- Runtime refs changed format:
core.action.python→core.python
Rust API
RuntimeTypeenum removed fromattune_common::models::enumsCreateRuntimeInputno longer hasruntime_typefieldRuntimeRepository::find_by_type()method removedRuntimeFixture::new()signature changed (removedruntime_typeparameter)
Acceptable Because
- Project is pre-production (no deployments, no users)
- Migration automatically handles data transformation
- No external API contracts affected (internal services only)
Next Steps
Immediate
- ✅ Code compiles and tests pass
- ✅ Migration tested and verified
- ✅ Documentation updated
Future Enhancements
- Version Detection: Parse runtime versions from verification output
- Version Constraints: Allow actions/sensors to require specific versions
- Distributed Scheduling: Route executions to workers with compatible runtimes
- Health Monitoring: Periodic re-verification of runtime availability
- API Endpoints: Expose runtime capabilities via REST API
Conclusion
Successfully unified runtime detection across worker and sensor services by:
- Removing artificial
runtime_typedistinction - Consolidating detection logic into shared module
- Enabling database-driven runtime configuration
- Reducing code duplication and maintenance burden
The system is now more maintainable, extensible, and better reflects the underlying reality that runtimes are shared infrastructure used by multiple service types.
Compilation Status: ✅ Clean
Test Status: ✅ Passing
Migration Status: ✅ Ready for deployment