Skip to main content
Adapters provide pluggable backend implementations for iii modules. You can create custom adapters to integrate with proprietary systems, cloud services, or specialized data stores.

Adapter Architecture

Each module can have multiple adapter implementations:
Adapters are selected via configuration:

Creating a Custom Adapter

Step 1: Define the Adapter Trait

First, define the interface your adapter must implement.
Reference the built-in QueueAdapter trait at src/modules/queue/mod.rs:20 for a complete example.

Step 2: Create Adapter Registration

Define how adapters are registered with the inventory system.

Step 3: Implement the Adapter

Create your adapter implementation.

Step 4: Register with the Macro

Create factory functions and register adapters.

Step 5: Create Module Config

Define configuration structure for your module.

Step 6: Implement the Module

Create the module that uses your adapter.

Step 7: Use the Module

Programmatically:
Via config.yaml:

Advanced Pattern: Decorator Adapters

You can create adapters that wrap other adapters (decorator pattern).
Configuration:

Built-in Adapter Examples

QueueAdapter Trait

Reference: src/modules/queue/mod.rs:20
Features:
  • Distributed tracing support (traceparent, baggage)
  • Dead letter queue (DLQ) handling
  • Conditional subscriptions
  • Per-subscriber queue configuration

Best Practices

Error Handling

  • Return anyhow::Result from constructors
  • Log errors with structured context
  • Implement graceful degradation for transient failures

Concurrency

  • Use async_trait for async trait methods
  • Prefer tokio::sync::RwLock for shared state
  • Use Arc for shared adapter instances

Configuration

  • Use serde::Deserialize for config structs
  • Provide sensible defaults
  • Validate configuration in constructors
  • Support environment variable expansion

Testing

  • Create mock adapters for testing
  • Test adapter registration
  • Test configuration parsing
  • Test concurrent access patterns

Performance

  • Minimize lock contention
  • Batch operations when possible
  • Use connection pooling for external services
  • Implement circuit breakers for reliability

Complete Example

See the full working example at examples/custom_queue_adapter.rs in the iii source code. This example demonstrates:
  • Custom adapter trait definition
  • Two adapter implementations (InMemory, Logging)
  • Decorator pattern for composable adapters
  • Module integration with EngineBuilder
  • YAML configuration support
Run the example:

Common Use Cases

Cloud Queue Services

  • AWS SQS/SNS adapter
  • Google Cloud Pub/Sub adapter
  • Azure Service Bus adapter

Message Brokers

  • Kafka adapter
  • NATS adapter
  • Pulsar adapter

Custom Storage

  • PostgreSQL-backed queue
  • MongoDB change streams
  • Custom database adapters

Hybrid Approaches

  • Multi-cloud queue adapter (failover)
  • Tiered storage (hot/cold data)
  • Caching adapters (Redis → S3)