Skip to main content

System Overview

iii uses a centralized engine + distributed worker architecture connected via WebSocket. The engine coordinates routing and discovery, while workers execute functions and manage trigger types.
The engine is a single Rust process. Workers are separate processes in any language (Node.js, Python, Rust, etc.) that connect via WebSocket.

The Engine

The engine is the central orchestration hub written in Rust. It manages:
  • WebSocket connections from workers
  • Function registry for discovering and routing calls
  • Trigger registry for event-to-function mappings
  • Worker registry for tracking connected workers
  • Modules for built-in functionality (HTTP API, Queue, Cron, etc.)
  • Invocation handling for request/response coordination

Engine Structure

All registries use thread-safe concurrent data structures (DashMap, Arc<RwLock<T>>) for lock-free access.

Default Ports

Starting the Engine

Workers

Workers are processes that connect to the engine and provide functions. Workers can be written in any language with a iii SDK.

Worker Capabilities

  • Register functions: Make code executable by the engine
  • Register trigger types: Declare support for event sources (http, cron, etc.)
  • Register triggers: Connect event sources to functions
  • Invoke functions: Call other functions across the system
  • Stream telemetry: Send OpenTelemetry traces, metrics, and logs

Worker Lifecycle

Worker Implementation

WebSocket Protocol

Workers and the engine communicate via JSON messages over WebSocket. The protocol is bidirectional and async.

Message Types

Example Protocol Flow

Protocol Message Schemas

Note: invocation_id is optional. Omit for fire-and-forget calls.
Either result or error will be set, not both.

Binary Protocol Extensions

In addition to JSON messages, iii supports binary WebSocket frames for high-performance telemetry:
  • OTLP prefix (OTLP): OpenTelemetry trace spans
  • MTRC prefix (MTRC): OpenTelemetry metrics
  • LOGS prefix (LOGS): OpenTelemetry logs
These prefixes allow SDKs to stream telemetry without JSON serialization overhead.

Invocation Flow

When a function is invoked, the engine coordinates the request/response lifecycle:

Same-Worker Invocation

Cross-Worker Invocation

Fire-and-Forget

Omit invocation_id for async calls that don’t need a response:
The engine routes the call but doesn’t track the invocation.

Modules

Modules are built-in engine plugins that provide functionality. They run inside the engine process and can register functions, trigger types, and services.

Default Modules

Module Configuration

Modules are configured in config.yaml:

Custom Modules

You can create custom modules in Rust:
See examples/custom_queue_adapter.rs for a complete example.

Observability

iii has built-in observability using OpenTelemetry:

Distributed Tracing

All function invocations are traced with parent-child span relationships:
Traces include:
  • traceparent: W3C Trace Context propagation
  • baggage: Cross-cutting context metadata
  • Automatic span creation and linking

Metrics

Engine metrics exported on :9464/metrics (Prometheus format):
  • iii_workers_active: Current worker count
  • iii_workers_spawns_total: Total workers connected
  • iii_functions_registered_total: Total functions registered
  • iii_invocations_total: Function invocation count
  • iii_invocation_duration_seconds: Invocation latency histogram

Logs

Structured logging with tracing:

Scalability Considerations

Horizontal Workers

Add more workers to scale function execution capacity

Single Engine

Engine is single-process, vertically scaled (multi-threaded Rust)

Function Routing

O(1) hash lookup, no coordination overhead

WebSocket Limits

Tested with 10,000+ concurrent worker connections
The engine is currently single-instance. For HA deployments, use external load balancers with session affinity, or run multiple isolated engine instances with separate worker pools.

Security

Network Security

  • Engine binds to 127.0.0.1 by default (localhost only)
  • Configure host: 0.0.0.0 to accept external connections
  • Use TLS-terminating reverse proxy (Caddy, nginx) for production

Worker Authentication

Currently, worker connections are unauthenticated. For production:
  1. Run engine behind a firewall
  2. Use VPN or private networking
  3. Implement custom auth in modules

Function Invocation Security

  • HTTP functions support auth configurations (Bearer, API key)
  • External functions can use auth field for credentials
  • Internal function calls are trusted (no auth)

Next Steps

Functions

Learn about registering and invoking functions

Triggers

Connect event sources to functions

Configuration

Configure modules and engine settings

Development

Set up a local development environment