Adapters
Adapters allow iii Core Modules to integrate with external systems and swap implementations without changing module logic.
What are Adapters?
Adapters are pluggable backends for Core Modules. They implement specific interfaces that modules use to interact with external systems like databases, message brokers, or storage services.
Why Adapters?
Flexibility: Swap implementations without code changes
- Development: Use in-memory adapters for fast local testing
- Production: Use Redis adapters for distributed deployments
Integration: Connect to your existing infrastructure
- Use your existing Redis cluster
- Integrate with custom message brokers
- Store data in your preferred database
Extensibility: Build custom adapters for specific needs
- Integrate proprietary systems
- Implement custom caching strategies
- Add specialized logging backends
Available Adapters by Module
Event Module
Stream Module
Cron Module
Logging Module
Adapter Configuration
Adapters are configured in the config.yaml file within the module configuration:
modules:
- class: modules::event::EventModule
config:
adapter:
class: modules::event::adapters::RedisAdapter
config:
redis_url: ${REDIS_URL:redis://localhost:6379}Configuration Pattern:
- class: Full path to the adapter implementation
- config: Adapter-specific configuration object
Building Custom Adapters
You can create custom adapters by implementing the adapter interface for each module type.
Event Adapter Interface
#[async_trait]
pub trait EventAdapter: Send + Sync {
async fn emit(&self, topic: &str, event_data: Value);
async fn subscribe(&self, topic: &str, id: String, function_path: String);
async fn unsubscribe(&self, topic: &str, id: &str);
}Example: Logging Event Adapter
Wrapper adapter that logs all events while delegating to another adapter:
pub struct LoggingEventAdapter {
inner: Arc<dyn EventAdapter>,
}
#[async_trait]
impl EventAdapter for LoggingEventAdapter {
async fn emit(&self, topic: &str, event_data: Value) {
tracing::info!(
topic = %topic,
event_data = %event_data,
"Emitting event"
);
self.inner.emit(topic, event_data).await;
}
async fn subscribe(&self, topic: &str, id: String, function_path: String) {
tracing::info!(topic = %topic, "Subscribing to topic");
self.inner.subscribe(topic, id, function_path).await;
}
async fn unsubscribe(&self, topic: &str, id: &str) {
tracing::info!(topic = %topic, "Unsubscribing from topic");
self.inner.unsubscribe(topic, id).await;
}
}Adapter Selection Guide
| Module | Development | Production (Single) | Production (Multi-Instance) |
|---|---|---|---|
| Event | InMemory | Redis | Redis |
| Stream | Redis | Redis | Redis |
| Cron | N/A | N/A | Redis |
| Logging | File | File / Redis | Redis |
Notes:
- Development: Fast, simple, no external dependencies
- Single Instance: One engine instance, may need persistence
- Multi-Instance: Multiple engine instances, requires distributed coordination
Environment-Based Configuration
Use environment variables to switch adapters between environments:
modules:
- class: modules::event::EventModule
config:
adapter:
class: ${EVENT_ADAPTER:modules::event::adapters::InMemoryAdapter}
config:
redis_url: ${REDIS_URL:redis://localhost:6379}Deployment:
# Development
EVENT_ADAPTER=modules::event::adapters::InMemoryAdapter iii
# Production
EVENT_ADAPTER=modules::event::adapters::RedisAdapter \
REDIS_URL=redis://production.redis:6379 \
iii