Function Invocation
The funcs module calls registered functions synchronously or asynchronously. An executor can propagate request context, security identity, and implementation-specific call options. This page is an API reference; target IDs, arguments, and application data represent surrounding code.
Loading
local funcs = require("funcs")
call
Calls a registered function synchronously and waits for its result.
local result, err = funcs.call("app.api:get_user", user_id)
if err then
return nil, err
end
print(result.name)
| Parameter | Type | Description |
|---|---|---|
target |
string | Function ID in format "namespace:name" |
...args |
any | Arguments passed to the function |
Returns: result, error
The target uses the namespace:name format.
async
Starts a function call and returns a Future immediately. Futures allow other work to continue while the call runs and support multiple concurrent calls.
-- Start heavy computation without blocking
local future, err = funcs.async("app.process:analyze_data", large_dataset)
if err then
return nil, err
end
-- Do other work while computation runs...
-- Wait for result when ready
local ch = future:response()
local _, open = ch:receive()
if not open then
return nil, errors.new("future response channel closed")
end
local payload, result_err = future:result()
if result_err then
return nil, result_err
end
local result, data_err = payload:data()
if data_err then return nil, data_err end
| Parameter | Type | Description |
|---|---|---|
target |
string | Function ID in format "namespace:name" |
...args |
any | Arguments passed to the function |
Returns: Future, error
new
Creates an Executor for calls that need custom context, security identity, or call options.
local exec = funcs.new()
Returns: Executor
Executor
An executor stores call context and options. Its configuration methods return new executor instances, allowing a base configuration to be reused.
with_context
Adds request-scoped values that will be available to the called function, such as trace IDs, session data, or feature flags.
local ctx = require("ctx")
-- Propagate request context to downstream services
local request_id, ctx_err = ctx.get("request_id")
if ctx_err then return nil, ctx_err end
local exec, err = funcs.new():with_context({
request_id = request_id,
feature_flags = {dark_mode = true}
})
if err then return nil, err end
local user, err = exec:call("app.api:get_user", user_id)
if err then return nil, err end
| Parameter | Type | Description |
|---|---|---|
values |
table | Key-value pairs to add to context |
Returns: Executor, error
with_actor
Sets the security actor used for authorization checks in the called function.
local security = require("security")
local actor = security.actor() -- Get current user's actor
-- Call admin function with user's credentials
local exec, err = funcs.new():with_actor(actor)
if err then return nil, err end
local result, err = exec:call("app.admin:delete_record", record_id)
if err and err:kind() == errors.PERMISSION_DENIED then
return nil, errors.new({kind = errors.PERMISSION_DENIED, message = "User cannot delete records"})
end
| Parameter | Type | Description |
|---|---|---|
actor |
Actor | Security actor (from security module) |
Returns: Executor, error
with_scope
Sets the security scope for called functions. The scope defines the permissions available to the call.
local security = require("security")
local scope = security.new_scope()
local exec, err = funcs.new():with_scope(scope)
if err then return nil, err end
| Parameter | Type | Description |
|---|---|---|
scope |
Scope | Security scope (from security module) |
Returns: Executor, error
with_options
Sets call options such as the retry policy or the overlay network. Options are merged over any preset options of the target function entry.
-- Retry transient failures up to 5 times with exponential backoff
local exec = funcs.new():with_options({
retry = { max_attempts = 5, initial_delay = 100 }
})
local result, err = exec:call("app.external:fetch_data", query)
if err then
-- All attempts failed, or the error was not retryable
end
| Parameter | Type | Description |
|---|---|---|
options |
table | Call options |
| Option | Type | Description |
|---|---|---|
retry.max_attempts |
int | Maximum attempts including the first (1 disables retry) |
retry.initial_delay |
int/duration | Delay before first retry (ms or duration string), default 100 |
retry.max_delay |
int/duration | Upper bound for the backoff delay (ms or duration string), default 10s |
retry.backoff_factor |
number | Multiplier applied to the delay after each attempt, default 2.0 |
retry.jitter |
number | Random jitter fraction applied to each delay, default 0.1 |
retry.retry_kinds |
string[] | Only retry errors of these kinds; by default every kind except Invalid, PermissionDenied and Internal is retried |
retry.skip_kinds |
string[] | Never retry errors of these kinds |
network |
string | Registry ID of an overlay network to route the call's outbound traffic through; requires the network.select permission |
Only retryable errors trigger retries; non-retryable errors surface immediately. Temporal activity options are described in Activities.
The runtime-defined option is:
| Recognized option | Type | Description |
|---|---|---|
network |
string | Registry ID of the outbound network.* entry |
Returns: Executor, error
Selecting a network requires network.select permission on that network ID.
call and async
The executor versions of call and async use its configured context and options.
-- Build reusable executor with context
local exec = funcs.new()
:with_context({trace_id = "abc-123"})
:with_options({retry = {max_attempts = 3}})
-- Make multiple calls with same context
local users, users_err = exec:call("app.api:list_users")
if users_err then return nil, users_err end
local posts, posts_err = exec:call("app.api:list_posts")
if posts_err then return nil, posts_err end
Future Invocation Summary
async() returns a future representing an in-progress invocation. The methods below cover the caller-facing steps for receiving, inspecting, or canceling that invocation. See Future for the Future object reference.
response and channel
Returns the channel used to receive the result.
local time = require("time")
local future, err = funcs.async("app.api:slow_operation", data)
if err then
return nil, err
end
local ch = future:response() -- or future:channel()
local timeout, err = time.after("5s")
if err then
return nil, err
end
local result = channel.select {
ch:case_receive(),
timeout:case_receive()
}
Returns: Channel
The response channel signals completion. After it becomes ready, call future:result() to obtain the cached value or the called function's error.
is_complete
Checks whether the future has completed without blocking.
while not future:is_complete() do
-- do other work
local _, sleep_err = time.sleep("100ms")
if sleep_err then return nil, sleep_err end
end
local result, err = future:result()
Returns: boolean
is_canceled
Returns true after cancellation is requested. This does not mean the operation has finished. See the cancellation limitation below.
if future:is_canceled() then
print("Cancellation requested")
end
Returns: boolean
result
Returns the cached result when complete or nil, nil while the operation is pending. Native futures complete only after the call frame and its owned resources are released. Requesting cancellation does not replace the eventual result; it may still be a success. Temporal workflow futures retain their recorded behavior: a marked-canceled future returns errors.CANCELED.
local value, err = future:result()
if err then
print("Failed:", err:message())
elseif value then
local data, data_err = value:data()
if data_err then return nil, data_err end
print("Got:", data)
end
Returns: Payload|table|nil, error|nil
error
Returns the operation error when the future has failed.
local err, has_error = future:error()
if has_error then
print("Error kind:", err:kind())
end
Returns: error|nil, boolean
This method returns a non-retryable INTERNAL wrapper for a failed operation. Use result() to preserve the called function's original error metadata.
cancel
Requests cancellation of the asynchronous operation.
local canceled, err = future:cancel()
if err then return nil, err end
Returns: boolean, error
cancel() is not a stable cross-provider contract. Do not use cancellation for application correctness; time out locally and ignore a late result until the runtime separates provider cancellation.
Parallel Operations
Combine async with channel.select to run and collect multiple calls concurrently.
-- Start multiple operations in parallel
local f1, err = funcs.async("app.api:get_user", user_id)
if err then return nil, err end
local f2, err = funcs.async("app.api:get_orders", user_id)
if err then return nil, err end
local f3, err = funcs.async("app.api:get_preferences", user_id)
if err then return nil, err end
-- Wait for all to complete using channels
local user_ch = f1:channel()
local orders_ch = f2:channel()
local prefs_ch = f3:channel()
local pending = {
[user_ch] = {name = "user", future = f1},
[orders_ch] = {name = "orders", future = f2},
[prefs_ch] = {name = "preferences", future = f3}
}
local results = {}
while next(pending) do
local cases = {}
for ch in pairs(pending) do
cases[#cases + 1] = ch:case_receive()
end
local r = channel.select(cases)
local completed = pending[r.channel]
pending[r.channel] = nil
local payload, result_err = completed.future:result()
if result_err then
return nil, result_err
end
local data, data_err = payload:data()
if data_err then
return nil, data_err
end
results[completed.name] = data
end
Permissions
Function operations are subject to security policy evaluation.
| Action | Resource | Description |
|---|---|---|
funcs.call |
Function ID | Call a specific function |
funcs.context |
context |
Use with_context() to set custom context |
funcs.security |
security |
Use with_actor() or with_scope() |
network.select |
Network ID | Use with_options({network = ...}) to select an overlay network |
Errors
| Condition | Kind | Retryable |
|---|---|---|
| Target empty | errors.INVALID |
no |
| Namespace missing | errors.INVALID |
no |
| Name missing | errors.INVALID |
no |
| Permission denied | errors.PERMISSION_DENIED |
no |
| Async outside a process | errors.INTERNAL |
no |
| Subscribe failed | errors.INTERNAL |
no |
| Async start dispatch failed | errors.INTERNAL |
no |
| Function error | varies | varies |
See Error Handling for working with errors.