Files
runner_v/src/README.md
Timur Gordon 010ecc7c71 initial commit
2025-08-26 14:47:52 +02:00

270 lines
8.0 KiB
Markdown

# V Lang Actor Interface
This module provides a V lang port of the Rust actor trait interface for the Hero Baobab system. It enables implementing actors in V lang with a simple interface: implement `process_job` and use `spawn` to run the actor.
## Architecture
The V lang actor interface mirrors the Rust implementation with these key components:
```text
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ SyncActor │ │ AsyncActor │ │ MyCustomActor │
│ │ │ │ │ │
│ process_job() │ │ process_job() │ │ process_job() │
│ (sequential) │ │ (concurrent) │ │ (custom logic) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
└───────────────┬───────────────────────────────┘
┌───────▼───────┐
│ Actor Interface│
│ │
│ spawn_actor() │
│ process_job() │
│ config │
└───────────────┘
```
## Core Components
### Actor Interface
All actors must implement the `Actor` interface:
```v
pub interface Actor {
// Process a single job - must be implemented by concrete actors
process_job(job Job, mut redis_conn redisclient.Redis) !
// Get the actor type identifier
actor_type() string
// Get the actor ID
actor_id() string
// Get the Redis URL
redis_url() string
// Get the database path
db_path() string
// Check if tasks should be preserved
preserve_tasks() bool
}
```
### ActorConfig
Configuration structure for all actors:
```v
pub struct ActorConfig {
pub:
actor_id string
db_path string
redis_url string
preserve_tasks bool
default_timeout ?time.Duration // Optional timeout for async actors
}
```
### Job Structure
Jobs processed by actors:
```v
pub struct Job {
pub mut:
id string
caller_id string
context_id string
script string
status JobStatus
result string
error string
created_at time.Time
started_at time.Time
finished_at time.Time
}
```
## Built-in Actor Implementations
### SyncActor
Processes jobs sequentially, one at a time:
```v
import freeflowuniverse.herolib.lib.baobab.actor
// Create configuration
config := actor.new_actor_config(
'sync_actor_1',
'/path/to/database',
'redis://localhost:6379',
false
)
// Create and spawn sync actor
sync_actor := actor.new_sync_actor(config)!
mut shutdown_chan := chan bool{cap: 1}
go actor.spawn_actor(sync_actor, mut shutdown_chan)
// Later, shutdown the actor
shutdown_chan <- true
```
### AsyncActor
Processes jobs concurrently with timeout support:
```v
import time
import freeflowuniverse.herolib.lib.baobab.actor
// Create configuration with timeout
mut config := actor.new_actor_config(
'async_actor_1',
'/path/to/database',
'redis://localhost:6379',
false
)
config = config.with_default_timeout(time.Duration(300 * time.second))
// Create and spawn async actor
async_actor := actor.new_async_actor(config)!
mut shutdown_chan := chan bool{cap: 1}
go actor.spawn_actor(async_actor, mut shutdown_chan)
// Later, shutdown the actor
shutdown_chan <- true
```
## Creating Custom Actors
To implement a custom actor, simply implement the `Actor` interface:
```v
import freeflowuniverse.herolib.lib.baobab.actor
struct MyCustomActor {
pub:
config actor.ActorConfig
mut:
engine rhai.Engine
// Add your custom fields here
}
pub fn new_custom_actor(config actor.ActorConfig) !MyCustomActor {
mut engine := rhai.new_engine()!
return MyCustomActor{
config: config
engine: engine
}
}
// Implement the Actor interface
pub fn (mut actor MyCustomActor) process_job(job actor.Job, mut redis_conn redisclient.Redis) ! {
// Your custom job processing logic here
// Update job status to started
actor.update_job_status(mut redis_conn, job.id, .started)!
// Execute the script (or your custom logic)
result := actor.execute_job_with_engine(mut actor.engine, job, actor.config.db_path)!
// Update job status to finished and set result
actor.update_job_status(mut redis_conn, job.id, .finished)!
actor.set_job_result(mut redis_conn, job.id, result)!
// Clean up if needed
actor.cleanup_job(mut redis_conn, job.id, job.context_id, actor.config.preserve_tasks)!
}
// Implement required interface methods
pub fn (actor MyCustomActor) actor_type() string { return 'MyCustomActor' }
pub fn (actor MyCustomActor) actor_id() string { return actor.config.actor_id }
pub fn (actor MyCustomActor) redis_url() string { return actor.config.redis_url }
pub fn (actor MyCustomActor) db_path() string { return actor.config.db_path }
pub fn (actor MyCustomActor) preserve_tasks() bool { return actor.config.preserve_tasks }
// Usage
config := actor.new_actor_config('my_actor', '/db/path', 'redis://localhost:6379', false)
custom_actor := new_custom_actor(config)!
mut shutdown_chan := chan bool{cap: 1}
go actor.spawn_actor(custom_actor, mut shutdown_chan)
```
## Key Features
### Unified Interface
- Same `spawn_actor()` function works with all actor implementations
- Consistent configuration and lifecycle management
- Clean separation between actor logic and infrastructure
### Redis Integration
- Automatic Redis connection management
- Job polling from actor-specific queues (`hero:job:actor_queue:{actor_id}`)
- Job status tracking and result storage
- Optional job cleanup based on `preserve_tasks` setting
### Script Execution
- Rhai script engine integration
- Automatic job context setup (DB_PATH, CALLER_ID, CONTEXT_ID)
- Error handling and status updates
### Graceful Shutdown
- Channel-based shutdown signaling
- Proper cleanup of resources
- Support for cancelling running jobs (AsyncActor)
## Job Processing Flow
1. **Job Polling**: Actor polls Redis queue using BLPOP
2. **Job Loading**: Load job details from Redis hash
3. **Status Update**: Mark job as "started"
4. **Script Execution**: Execute Rhai script with job context
5. **Result Storage**: Store result or error in Redis
6. **Status Update**: Mark job as "finished" or "error"
7. **Cleanup**: Optionally remove job from Redis
## Error Handling
All operations include comprehensive error handling:
- Redis connection failures
- Job loading errors
- Script execution errors
- Timeout handling (AsyncActor)
- Graceful degradation and logging
## Migration from Rust
This V lang implementation provides the same functionality as the Rust version:
- ✅ Actor trait abstraction
- ✅ Sync and async actor implementations
- ✅ Unified spawn interface
- ✅ Redis job queue integration
- ✅ Rhai script execution
- ✅ Job lifecycle management
- ✅ Error handling and logging
- ✅ Graceful shutdown
## Dependencies
The actor interface depends on these herolib modules:
- `freeflowuniverse.herolib.clients.redisclient` - Redis operations
- `freeflowuniverse.herolib.data.rhai` - Script execution
- `freeflowuniverse.herolib.core.base` - Base utilities
## Usage Summary
To implement an actor in V lang:
1. **Create ActorConfig**: Configure actor ID, database path, Redis URL, etc.
2. **Implement Actor Interface**: Create a struct that implements the `Actor` interface
3. **Implement process_job()**: Add your job processing logic
4. **Use spawn()**: Call `spawn_actor()` to start the actor loop
That's it! The interface handles all the Redis polling, job management, and infrastructure concerns automatically.