Skip to main content

Why this change

iii is built on three primitives: Workers, Functions, and Triggers. Every concept in the system maps to one of these:
  • Workers are long-running processes that connect to the engine and provide capabilities — HTTP serving, queue processing, cron scheduling, state management, stream handling, and anything else the engine needs to operate.
  • Functions are units of work. A worker registers functions, and any other worker (or the engine itself) can invoke them by ID.
  • Triggers are the rules that cause functions to fire — an HTTP request, a cron schedule, a queue message, a state change.
Before this release, the engine-internal components that provide capabilities (HTTP, queues, cron, etc.) were called “modules”. Meanwhile, the remote SDK processes that register functions were called “workers”. This created a confusing split: two different names for things that serve the same role — connecting to the engine and doing work. Modules are workers. They run alongside the engine, register functions, react to triggers, and provide capabilities to the rest of the system. The only difference was the name. By renaming modules to workers, every component in the system uses the same vocabulary. The engine config lists workers:. The SDK connects workers. The docs describe workers. There is one concept, one name, and one mental model. The previous Worker struct (representing a connected SDK runtime over WebSocket) has been renamed to WorkerConnection to avoid collision.

What changed

Config YAML

The top-level modules: key is now workers:, and each entry uses name: with a short identifier instead of class: with a Rust-style path.
# Before
modules:
  - class: modules::stream::StreamModule
    config:
      port: 3112

# After
workers:
  - name: iii-stream
    config:
      port: 3112
The modules: key is still accepted for backward compatibility, but workers: is the canonical form going forward.

Worker name mapping

Old class: valueNew name: value
modules::worker::WorkerModuleiii-worker-manager
modules::stream::StreamModuleiii-stream
modules::state::StateModuleiii-state
modules::api::RestApiModuleiii-http
modules::pubsub::PubSubModuleiii-pubsub
modules::observability::OtelModuleiii-observability
modules::queue::QueueModuleiii-queue
modules::http_functions::HttpFunctionsModuleiii-http-functions
modules::cron::CronModuleiii-cron
modules::shell::ExecModuleiii-exec
modules::bridge_client::BridgeClientModuleiii-bridge

Adapter name mapping

Adapter entries inside config.adapter also switched from class: to name: with short identifiers:
Old adapter class:New adapter name:
modules::stream::adapters::KvStorekv
modules::stream::adapters::RedisAdapterredis
modules::stream::adapters::Bridgebridge
modules::state::adapters::KvStorekv
modules::state::adapters::RedisAdapterredis
modules::state::adapters::Bridgebridge
modules::pubsub::LocalAdapterlocal
modules::pubsub::RedisAdapterredis
modules::queue::BuiltinQueueAdapterbuiltin
modules::queue::RedisAdapterredis
modules::queue::RabbitMQAdapterrabbitmq
modules::queue::adapters::Bridgebridge
modules::cron::KvCronAdapterkv
modules::cron::RedisCronAdapterredis

Full config example

modules:
  - class: modules::stream::StreamModule
    config:
      port: 3112
      adapter:
        class: modules::stream::adapters::KvStore
        config:
          store_method: file_based
          file_path: ./data/stream_store

  - class: modules::state::StateModule
    config:
      adapter:
        class: modules::state::adapters::KvStore
        config:
          store_method: file_based
          file_path: ./data/state_store.db

  - class: modules::api::RestApiModule
    config:
      port: 3111

  - class: modules::observability::OtelModule
    config:
      enabled: true

  - class: modules::queue::QueueModule
    config:
      adapter:
        class: modules::queue::BuiltinQueueAdapter

  - class: modules::pubsub::PubSubModule
    config:
      adapter:
        class: modules::pubsub::LocalAdapter

  - class: modules::cron::CronModule
    config:
      adapter:
        class: modules::cron::KvCronAdapter

Rust API

Crate module path

The modules Rust module has been renamed to workers, and the trait definition file moved from module.rs to traits.rs.
// Before
use iii::modules::config::EngineBuilder;
use iii::modules::module::Module;
use iii::modules::registry::ModuleRegistration;

// After
use iii::workers::config::EngineBuilder;  // also re-exported as iii::EngineBuilder
use iii::workers::traits::Worker;
use iii::workers::registry::WorkerRegistration;

Trait renames

BeforeAfter
trait Moduletrait Worker
trait ConfigurableModuletrait ConfigurableWorker
Module::make_module()Worker::make_worker()
Module::create() -> Box<dyn Module>Worker::create() -> Box<dyn Worker>
ConfigurableModule::DEFAULT_ADAPTER_CLASSConfigurableWorker::DEFAULT_ADAPTER_NAME
ConfigurableModule::default_adapter_class()ConfigurableWorker::default_adapter_name()
ConfigurableModule::adapter_class_from_config()ConfigurableWorker::adapter_name_from_config()

Type alias and struct renames

BeforeAfter
ModuleFutureWorkerFuture
ModuleFactoryWorkerFactory
ModuleInfoWorkerInfo
ModuleRegistryWorkerRegistry
ModuleEntryWorkerEntry
ModuleRegistrationWorkerRegistration

Macro renames

BeforeAfter
register_module!(class, Type, ...)register_worker!(name, Type, ...)

EngineBuilder API

BeforeAfter
EngineBuilder::add_module(class, config)EngineBuilder::add_worker(name, config)
EngineBuilder::register_module::<M>(class)EngineBuilder::register_worker::<M>(name)

Implementation struct renames

BeforeAfter
WorkerModuleWorkerManager
StreamCoreModuleStreamWorker
StateCoreModuleStateWorker
RestApiCoreModuleHttpWorker
PubSubCoreModulePubSubWorker
OtelModuleObservabilityWorker
QueueCoreModuleQueueWorker
HttpFunctionsModuleHttpFunctionsWorker
CronCoreModuleCronWorker
ExecCoreModuleExecWorker
BridgeClientModuleBridgeClientWorker
TelemetryModuleTelemetryWorker
EngineFunctionsModuleEngineFunctionsWorker
ExternalModuleExternalWorker

WorkerConnection (was Worker)

The Worker struct that represented a connected remote SDK runtime has been renamed to WorkerConnection and moved to a separate module.
BeforeAfter
crate::workers::Workercrate::worker_connections::WorkerConnection
crate::workers::WorkerRegistrycrate::worker_connections::WorkerConnectionRegistry
crate::workers::WorkerStatuscrate::worker_connections::WorkerConnectionStatus
crate::workers::WorkerTelemetryMetacrate::worker_connections::WorkerConnectionTelemetryMeta

Migration examples

Custom worker

use iii::modules::module::Module;

pub struct MyModule { /* ... */ }

#[async_trait]
impl Module for MyModule {
    fn name(&self) -> &'static str { "MyModule" }
    async fn create(engine: Arc<Engine>, config: Option<Value>) -> anyhow::Result<Box<dyn Module>> {
        Ok(Box::new(MyModule { /* ... */ }))
    }
    async fn initialize(&self) -> anyhow::Result<()> { Ok(()) }
}

iii::register_module!("my::custom::Module", MyModule, enabled_by_default = true);

Custom adapter

iii::register_adapter!(
    <MyAdapterRegistration>
    "modules::my_worker::MyAdapter",
    make_adapter
);

Migration checklist

  • Rename modules: to workers: in all config YAML files
  • Replace class: with name: using the new short identifiers (see tables above)
  • Replace adapter class: with name: using short identifiers (kv, redis, builtin, etc.)
  • Update Rust imports from iii::modules:: to iii::workers::
  • Update iii::modules::module::Module to iii::workers::traits::Worker
  • Replace register_module! with register_worker!
  • Replace add_module() / register_module() on EngineBuilder with add_worker() / register_worker()
  • Rename any *Module / *CoreModule struct references to the new *Worker / *Manager names
  • Update crate::workers::Worker references to crate::worker_connections::WorkerConnection