Installation
Initialization
register_worker
Register the worker with a iii instance, returns a connected worker client. Blocks up to 30 seconds for the WebSocket connection to be established. If the engine is not reachable in time, a warning is logged and the client is returned anyway; it keeps retrying in the background and flushes registrations once connected. Useadd_connection_state_listener to observe the actual transition.
Signature
- Parameters
- Example
Methods
register_function
Register a function with the engine. Pass a handler for local execution, or anHttpInvocationConfig
for HTTP-invoked functions (Lambda, Cloudflare Workers, etc.).
Handlers can be synchronous or asynchronous. Sync handlers are
automatically wrapped with run_in_executor so they do not
block the event loop. Each handler receives a data argument
containing the call’s payload, and may optionally accept a second
metadata argument carrying per-invocation metadata (e.g.
def handler(data, metadata=None) or def handler(data, *, metadata=None)). Metadata is only forwarded to handlers that
declare a parameter literally named metadata, so existing
handlers, including ones with unrelated extra parameters,
*args, or **kwargs, keep working unchanged.
The handler’s return value is what the function’s observers observe.
An event source’s handler returns the event it is called with. What
this worker does when the function is observed is set with the hook
methods (on_observer_added, on_observer_removed,
on_observation_match, on_observation_deliver) on the client by id or
on the returned FunctionRef. Set on_observer_added and
on_observer_removed by id before registering so they run for every
observer: the engine may announce an observer before a hook set on the
FunctionRef is in place.
request_format and response_format are auto-extracted
from the handler’s type hints when omitted or passed as None
(the default). To opt out of auto-extraction, pass an explicit
schema (RegisterFunctionFormat or dict). This behavior
is Python-specific; the Node SDK relies on explicit schemas because
TypeScript types are erased at runtime.
Signature
- Parameters
- Example
str
required
Unique string identifier for the function.
RemoteFunctionHandler | HttpInvocationConfig
required
A callable handler or
HttpInvocationConfig. Callable handlers receive data (the call’s payload) as the first argument and may optionally accept metadata (per-invocation metadata) as a second argument; they may return a value.str | None
Human-readable description of what the function does.
dict[str, Any] | None
Arbitrary metadata attached to the function.
RegisterFunctionFormat | dict[str, Any] | None
Schema describing expected input. When
None (default), auto-extracted from the handler’s first-parameter type hint. Pass an explicit schema to override; there is no way to register with no schema when the handler is typed.RegisterFunctionFormat | dict[str, Any] | None
Schema describing the handler’s return value, what observers observe. Same auto-extraction semantics as
request_format.Any
JSON Schema (or a Pydantic model) of the observers’
args; the engine validates them (INVALID_ARGS). A function without it takes no args.bool
Only this worker may call the function; others may observe it. This worker’s own calls pass the input and the result by reference: the handler and hooks treat both as read-only.
bool
False: nobody may observe the function (NOT_OBSERVABLE), for functions whose payloads carry credentials.bool
Calls this worker makes to its own function run in-process once the engine confirmed it (default
True). Like a remote invocation, each local call to a sync handler runs on a thread of its own (one per call, not pooled), so the caller can stop waiting at its timeout. A sync handler that blocks for long should be async, or set False so its calls go through the engine (also for a handler that relies on engine-side effects).call
Call a function and return its result. The routing behavior and return type depend on theaction field:
- No action: synchronous, waits for the function to return.
CallAction.Enqueue(...): async via named queue, returns a dict withmessageReceiptId.CallAction.Void(): fire-and-forget, returnsNone.
dispatch="remote" (or
action=Enqueue) always goes through the engine. Whatever a local
handler raises, BaseExceptions such as KeyboardInterrupt and
SystemExit included, reaches the caller as
InvocationError("invocation_failed") with the original as its
__cause__ (for a Void call nothing reaches the caller: the
error is logged).
metadata is any JSON value; the handler receives it beside the
payload, and None is no metadata.
A request with observer (an Observer of a function this
worker hosts) calls through it: the engine runs the observer’s target
with its policy (max_fires, expiry, max_in_flight), metadata
sidecar and loop guard, and the call resolves to the target’s result.
It takes no metadata: the target’s metadata argument is the
observer’s registration metadata, and a request that names metadata
raises ValueError before anything is sent.
The payload goes as given: filters are applied where the worker
chooses observers: iii’s delivery, or obs.matches(call) in an
on_observation_deliver. A host also calls through an observer to
send it something of its own, such as its initial state once it is
accepted (see Observer.accepted).
Signature
- Parameters
- Example
dict[str, Any] | CallRequest
required
A
CallRequest or dict with function_id (or observer), payload, and optional action / timeout_ms / metadata / namespace / dispatch ("auto", the default, or "remote").observe
Observes a function: whensource runs, target runs. Every
call of the source function that passes source["filters"] invokes
target, a registered function, with the Observed payload:
the top-level fields plus what source["capture"] names that applies
to the outcome (input, output or error, caller,
metadata). capture also decides which outcomes fire the target.
The worker that hosts the source can decide otherwise
in its on_observation_deliver.
Returns synchronously, also before the connection is up; the observer
is replayed with the same id on every reconnect. The handle holds its
id until its dispose() is called or the engine disposes it; the
id is free again at once after that. Errors
(INVALID_ARGS, INVALID_FILTER, FORBIDDEN,
NOT_OBSERVABLE, the rejection of the source’s worker,
UNSUPPORTED against an engine without observe) show up as state
error and make ready() raise ObserveRejection. An
error answer to the handle’s observe or to its replay after a
reconnect is the engine’s refusal and the handle’s final answer: the
engine holds no observer for it, it is not replayed, it holds its id
until its dispose(), and that dispose() sends nothing. An
observer that moves to error after its answer stays held: it is
replayed, and its dispose() sends an unobserve.
Signature
- Parameters
- Example
str | ObserveSource | dict[str, Any]
required
What is observed: a function id, or
function_id, namespace, args (read by the worker that hosts the function, validated against its args_format), filters, and capture.Target
required
The function to invoke: its id, or
{"function_id": ..., "namespace": ...}. Register it first; until then the observer stays pending.ObserverOptions | dict[str, Any] | None
id, max_fires, expires_in_ms, max_in_flight, metadata (the activation’s metadata sidecar).trigger
Call a function:call under its 0.25 name.
Signature
Parameters
dict[str, Any] | CallRequest
required
add_connection_state_listener
Subscribe to connection-state transitions. The handler is fired immediately with the current state (on the caller’s thread), then once per transition. Transitions fire on the SDK’s background event-loop thread: keep handlers fast and do not call sync SDK methods from them (they would raiseRuntimeError).
Treat calls as state notifications, not edges. A state may rarely
be observed twice around subscription. Registering the same handler
twice fires it twice. Returns an idempotent unsubscribe function
that removes only its own registration.
Signature
- Parameters
- Example
ConnectionStateCallback
required
call_async
Call a function and return its result (on any event loop). The routing behavior and return type depend on theaction field:
- No action: synchronous, waits for the function to return.
CallAction.Enqueue(...): async via named queue, returns a dict withmessageReceiptId.CallAction.Void(): fire-and-forget, returnsNone.
dispatch="remote" (or action=Enqueue)
always goes through the engine. A request with observer calls
through it, as for call.
Signature
- Parameters
- Example
dict[str, Any] | CallRequest
required
A
CallRequest or dict with function_id (or observer), payload, and optional action / timeout_ms / metadata / namespace / dispatch ("auto" or "remote").connect_async
Connect to the III Engine via WebSocket. Initializes OpenTelemetry (if configured), attaches the event loop, and establishes the WebSocket connection. This is called automatically during construction; use it only if you need to reconnect manually from an async context. Signaturecurrent_invocation
The invocation the calling code runs in (in every handler, remote or local), orNone outside any handler.
Signature
Example
get_address
Return the engine address this worker resolved to. The explicitregister_worker argument, else III_URL, else
DEFAULT_ENGINE_URL. Mirrors the Rust SDK’s address() and the
Node SDK’s getAddress().
Signature
get_connection_state
Return the current WebSocket connection state. SignatureExample
is_observed
Whether a call of a function this worker hosts would reach anyone, so a source can skip building an event nobody wants. Withoutcall: whether the function has any active observer (one
load). With call (a Call or a partial one,
{"input": ...}) on a function matched by keys
(on_observation_match): whether an observer is filed under one of
the call’s keys. On any other function the call is ignored.
Signature
observers
The active observers of a function this worker hosts, as it sees them. Signature- Parameters
- Example
str
required
on_observation_deliver
Delivers each call of one function itself:hook(call, observers) receives the Call and the observers that matched
it (on_observation_match, or all of them), as a snapshot taken when
the call started, and what it returns (or raises) is what the caller
gets back. iii delivers nothing for that function: the hook calls
through observers (iii.call({"observer": obs, ...})) and applies
their capture and filters with obs.matches(call). Works as a
decorator (@iii.on_observation_deliver("fn::id")) and returns the
hook; None restores iii’s delivery.
The hook runs inside the function’s invocation, so the calls it makes
have that invocation as their caller. A sync hook runs on a thread of
its own. A function with a deliver hook needs an engine with
observe.v2.
Signature
on_observation_match
Sets which observers want each call of one function. By default every observer wants every call; iii’s delivery then applies their capture and filters, and anon_observation_deliver receives only the
observers that matched.
As a predicate, hook(obs, call) -> bool is asked once per
observation: for every call, once for each active observer, before
its filters; a predicate that raises counts as no match for that
observer. As keys, observer= and call= key functions each
return a string or strings, and an observer wants a call when they
share a key: the SDK computes an observer’s keys once, when it is
accepted, and files it under each, so a call costs one lookup per key
whatever the number of observers. An observer whose key function
raises is rejected (OBSERVE_REJECTED); a call whose key function
raises matches no observer. A match hook that raises is logged once
per function. Wildcards are keys too: file an observer of every table
under "primary|*|insert" and give a change the keys
"primary|orders|insert", "primary|orders|*",
"primary|*|insert" and "primary|*|*".
Works as a decorator for a predicate
(@iii.on_observation_match("fn::id")) and returns the hook (a
MatchKeys for the keys form); None removes it, and every
observer gets every call again. A match
hook set while the function has active observers is applied to them
on the SDK loop, which rebuilds the index from them. Predicates and
key functions are sync: they run on every call. A function with a
match hook needs an engine with observe.v2: against an older one
it stays unregistered, and UNSUPPORTED is logged once.
Signature
on_observer_added
Sets what runs when an observer is added, before it is accepted: for every function this worker hosts (on_observer_added(hook)), or
for one (on_observer_added("fn::id", hook)). Works as a decorator,
@iii.on_observer_added or @iii.on_observer_added("fn::id"), and
returns the hook; None removes it.
The worker’s hook runs, then the function’s; the observer is accepted
(acked, then active) once both resolved. A hook that raises rejects
the observer with the ObserveRejection it raised, or
OBSERVE_REJECTED; one still running after 30 s rejects it with
OWNER_TIMEOUT. Then the on_observer_removed of each level whose
hook already resolved runs. Hooks may be sync (on a thread of their
own) or async, and the hooks of one function run one at a time.
Hooks are stored by function id, so they can be set before the
function is registered (which makes them run for every observer) and
stay in place across unregister(). A hook set while the function
already has active observers runs for each of them at once (a raise
rejects that observer) and logs one warning. A second after the
connection is registered, and after the last hook set by id, a
warning names each hook id this worker has not registered.
Signature
on_observer_removed
Sets what runs when an accepted observer goes (onunobserve, on
disposal, after a late rejection): for every function this worker
hosts, or for one. The same forms as on_observer_added.
It runs exactly once for every accepted observer, the function’s hook
and then the worker’s, and never for an observer that was not
accepted. An error it raises is logged; the observer is removed
either way.
Signature
register_trigger
Removed in 0.26.0: raises an error that points toobserve.
Signature
Parameters
Any
Any
register_trigger_type
Removed in 0.26.0: raises an error that points toregister_function and the observer hooks.
Signature
Parameters
Any
Any
shutdown
Gracefully shut down the client, releasing all resources. Cancels any pending reconnection attempts, rejects all in-flight invocations with an error, closes the WebSocket connection, and stops the background event-loop thread. After this call the instance must not be reused. SignatureExample
shutdown_async
Gracefully shut down the client, releasing all resources. Cancels any pending reconnection attempts, rejects all in-flight invocations with an error, closes the WebSocket connection, and stops the background event-loop thread. After this call the instance must not be reused. SignatureExample
trigger_async
Call a function:call_async under its 0.25 name.
Signature
Parameters
dict[str, Any] | CallRequest
required
unregister_trigger_type
Removed in 0.26.0: raises an error that points toFunctionRef.unregister.
Signature
Parameters
Any
Any
Types
iii
Call · CallAction · CallActionEnqueue · CallActionVoid · Caller · EnqueueResult · InitOptions · InvocationContext · MatchKeys · MiddlewareFunctionInput · Observed · Observer · ObserverHandle · ObserverOptions · ObserveSource · StreamRequest · StreamResponse · TelemetryOptions
Call
One call of a function, as its observers observe it and itson_observation_match and on_observation_deliver hooks receive it.
CallAction
Factory for creating call actions used withcall().
CallActionEnqueue
Routes the call through a named queue for async processing. Requires thequeue worker in worker-compose.yaml and a matching
entry under that worker’s queue_configs.
Without it the call rejects with enqueue_error (no queue provider).
CallActionVoid
Fire-and-forget routing. No response is returned.Caller
Who started an invocation: the worker (worker_id / worker_name,
stamped by the engine), and the function and invocation the call was made
from (absent for top-level calls). parent is that handler’s own caller,
one level only.
EnqueueResult
Result returned when a function is called withCallAction.Enqueue.
InitOptions
Configuration options passed toregister_worker.
InvocationContext
The invocation the current code runs in, in every handler, remote or local. Returned byiii.current_invocation().
MatchKeys
on_observation_match as keys: an observer wants a call when they share
a key, and the SDK keeps an index instead of asking every observer.
MiddlewareFunctionInput
Input passed to the RBAC middleware function on every function invocation through the RBAC port.Observed
What an observer’s target receives when iii delivers: the top-level fields, plus whichever of the observer’scapture apply to the outcome.
Fields not captured, or that do not apply, are absent.
Observer
An observer as the worker that hosts its function sees it (on_observer_added, observers(), a deliver hook’s observers):
what was asked for. Never who observes, the observer’s metadata or its
policy.
The object stays the same for the observer’s whole lifetime, so a worker
keeps it in its own index (route table, consumers, …).
ObserverHandle
Whatiii.observe returns, synchronously.
The observer is replayed with the same id on every reconnect until it is
disposed. An error answer to its observe or to a replay is the
engine’s refusal and is final: the engine holds nothing for it, and it is
not replayed. State listeners are called in order, on a callback thread of
the SDK (never on the event loop that reads the engine’s frames), so they
may call the sync API.
ObserverOptions
The observer itself: its id, policy and metadata (the third argument ofiii.observe).
ObserveSource
The left side ofiii.observe: what is observed.
StreamRequest
Incoming streaming request received by a function that serves a streaming HTTP route.StreamResponse
Streaming response built on top of a ChannelWriter.TelemetryOptions
Worker metadata reported to the engine (language, framework, project).iii.channel
Channel · ChannelReader · ChannelWriter · StreamChannelRef
Channel
A streaming channel pair for worker-to-worker data transfer.ChannelReader
WebSocket-backed reader for streaming binary data and text messages.ChannelWriter
WebSocket-backed writer for streaming binary data and text messages.StreamChannelRef
Reference to a streaming channel for worker-to-worker data transfer.iii.engine
EngineFunctions · EngineSources
EngineFunctions
Engine function ids for internal operations (parity with the Node SDK).EngineSources
Ids of the engine-hosted functions that are called once per event: observe them withiii.observe(EngineSources.FUNCTIONS_CHANGED, target)
(parity with the Node SDK).
iii.errors
InvocationError · ObserveRejection · RegistrationRejectedError
InvocationError
Raised when an invocation dispatched by the SDK fails. Inspecterr.code to react to a specific category (e.g.
'FORBIDDEN' for RBAC denials, 'TIMEOUT' for timeouts). Catch
this class to handle every rejection. except Exception continues to
work because InvocationError inherits from Exception.
Attributes are read-only after construction. stacktrace is the
engine-side trace when the remote handler raised; it may include
internal file paths and should not be surfaced to end users. str(err)
intentionally never includes the stacktrace.
ObserveRejection
Rejects an observer with a code of its own. Raise it from anon_observer_added hook, at either level
(HTTP_ROUTE_CONFLICT, INVALID_CRON_EXPRESSION, …); any other
exception rejects the observer with OBSERVE_REJECTED. Raised from an
on_observation_deliver hook, its code is the error the caller gets. Also
what ObserverHandle.ready() and Observer.accepted() raise when the
observer turns error or disposed, with the engine’s or the hook’s
code (INVALID_ARGS, FORBIDDEN, UNSUPPORTED, …).
RegistrationRejectedError
Raised when the engine rejects this worker’s registration. The engine pushes aregistrationrejected message and closes the
connection on a registration collision (e.g. another live worker already
owns (namespace, worker_name)). This is fatal: the SDK does not
reconnect. Inspect the attributes to identify the conflict.
iii.protocol
CallRequest · MessageType · RegisterFunctionFormat · RegisterFunctionInput · RegisterFunctionMessage · SDK_FEATURES
CallRequest
Request object forcall() / call_async().
Name the function to call with function_id, or call through an
observer with observer: the call runs the observer’s target, and only
the worker that hosts the observed function may make it.
MessageType
Message types for iii communication.RegisterFunctionFormat
Format definition for function parameters.RegisterFunctionInput
Input for registering a function, matches Node.js RegisterFunctionInput.RegisterFunctionMessage
SDK_FEATURES
iii.runtime
FunctionRef
FunctionRef
A registered function: the client’s hook methods with its id filled in, its observers, andunregister().
Each hook method works as a decorator and as a plain call, returns the
hook, and removes the hook when given None. Hooks are stored by
function id, so they stay in place across unregister() and a later
registration of the same id.
The SDK loop runs on a thread of its own, so the engine may announce an
observer before a hook set here is in place: on_observer_added then
runs for that observer after it became active, and a warning says so.
For on_observer_added and on_observer_removed to run for every
observer, set them on the client by id before register_function.
iii.state
IState · StateDeleteInput · StateDeleteResult · StateEventData · StateEventType · StateGetInput · StateListInput · StateSetInput · StateSetResult · StateUpdateInput · StateUpdateResult
IState
Abstract interface for state management operations.StateDeleteInput
Input for deleting a state value.StateDeleteResult
Result of a state delete operation.StateEventData
Payload for state change events.StateEventType
Types of state change events.StateGetInput
Input for retrieving a state value.StateListInput
Input for listing all values in a state scope.StateSetInput
Input for setting a state value.StateSetResult
Result of a state set operation.StateUpdateInput
Input for atomically updating a state value.StateUpdateResult
Result of a state update operation.iii.stream
IStream · StreamDeleteInput · StreamDeleteResult · StreamGetInput · StreamListGroupsInput · StreamListInput · StreamSetInput · StreamSetResult · StreamUpdateInput · StreamUpdateResult
IStream
Abstract interface for stream operations. .. deprecated:: IStream is deprecated (iii-stream) and will be removed in an upcoming release. Behavior is unchanged for now. Migration guide: https://iii.dev/docs/upgrading/migrate-from-streams Defining a subclass emits aFutureWarning attributed to the line of the
class statement (once per subclass definition, never per request). Importing
this module does not warn.