Skip to main content

Registering a Function and Triggering it

Function registration is just passing a function, an id for the function to registerFunction({id}, func) (or the equivalent in other languages). These functions can then be Triggered from anywhere else in the application, and across language and service boundaries. Read more on that in the Cross-language Triggering section below. Once registered, math::add is triggerable from anywhere in the system. This example also stores each result in state so it can be aggregated later by a cron job.
math-add.ts

HTTP-Invoked Functions

Instead of passing a handler, you can register an external HTTP endpoint as a function. The engine makes the HTTP call when the function is triggered — no client-side HTTP code needed. This is useful for delegating work to external services like webhooks, serverless functions, or third-party APIs.
HTTP-invoked functions require HttpFunctionsModule to be enabled in your engine config. See the engine configuration guide for details.
Pass an HttpInvocationConfig as the second argument to registerFunction instead of a handler:
http-invoked.ts
HTTP-invoked functions behave like any other function — they can be triggered with trigger(), bound to any trigger type (queue, cron, state, etc.), and discovered by other services. The engine forwards the trigger data as the JSON request body and treats non-2xx responses or network errors as failures.

HttpInvocationConfig fields

Fields like token_key, secret_key, and value_key in auth config are environment variable names, not raw secrets. The engine resolves them from its process environment at invocation time.

Ways to Trigger Functions

As shown above functions can be triggered with trigger({ function_id, payload }) but there are actually three ways to trigger them and a way to register additional Triggers that fire Functions according to internal and external events.

trigger() — Await the result

trigger.ts

Fire-and-forget — trigger with TriggerAction.Void()

trigger-void.ts

Enqueue — trigger with TriggerAction.Enqueue({ queue })

Enqueue work to a named queue for async processing. The engine acknowledges with { messageReceiptId } when the job is accepted. The target function receives the payload when a worker processes it. Requires queues defined in iii-config.yaml — see Use Queues.
trigger-enqueue.ts

registerTrigger() — Run on an event

Bind a Function to an event source. The engine triggers it automatically when the event fires. Below are examples for common Trigger types: HTTP, Cron, and State.

HTTP

HTTP triggers receive an ApiRequest object with body, query_params, path_params, headers, and method. The handler returns an ApiResponse with status_code, body, and optional headers.
http-trigger.ts

Cron

This example aggregates all stored math results (from math::add above) every 30 minutes.
cron-trigger.ts

State

State triggers fire when a value in state changes. This example registers an external webhook as an HTTP-invoked function and binds it to a state trigger. When the order status changes, the engine POSTs the state event to the webhook URL automatically.
state-trigger.ts

Trigger Types

Cross-language triggering

Any Function can be Triggered anywhere regardless of language. The engine handles serialization and routing:
cross-language.ts
The triggering Function doesn’t know what language the target is written in or where it’s running. Once a Function is registered, every other part of the system can discover and trigger it. See Discovery for how this works, including built-in functions the engine provides.

Unregistering Functions and Triggers

Both registerFunction and registerTrigger return a reference with an unregister() method. Calling it removes the registration from the engine so the function or trigger stops receiving invocations.
unregister.ts

registerWorker, Function, and Trigger Registration is Synchronous

The registerWorker() call returns immediately rather than returning a Promise. This is intentional. Connection establishment happens asynchronously in the background. This design avoids requiring developers to wrap initialization in an async function or await the SDK before registering functions and triggers. Without this, every function and trigger definition would need to wait on initialization, adding boilerplate to every file. The trade-off: if code calls shutdown() immediately after registerWorker(), the connection may not yet be established, resulting in an error like WebSocket was closed before the connection was established. In practice this rarely matters — most applications register functions, respond to triggers, and run indefinitely.

Function IDs

Function IDs use a namespace::name convention but can be any arbitrary string. iii conventions recommend following this rule but the iii engine does not enforce it.
The iii:: prefix is reserved for internal engine functions. Function IDs cannot start with iii::.

Built-in Functions

The engine provides built-in functions that can be triggered the same way any other Function would be triggered. These handle common operations like state management, streaming, messaging, and observability.

State

Persistent key-value storage with scoped namespaces.

Stream

Real-time data streams with hierarchical organization.

Queue

Durable message queue for async processing.

PubSub

Publish-subscribe messaging for event broadcasting.

Engine

Internal engine functions for introspection and management.
The Engine module is mandatory and always loaded.

Observability

Logging, tracing, and metrics. The Observability module is disabled by default and must be enabled in engine config.