# Functions
_Path: en/lua/core/funcs_
## Table of Contents
- Function Invocation
## Content
# Function Invocation
The primary way to call other functions in Wippy. Execute registered functions synchronously or asynchronously across processes, with full support for context propagation, security credentials, and timeouts. This module is central to building distributed applications where components need to communicate.
## Loading
```lua
local funcs = require("funcs")
```
## call
Calls a registered function synchronously. Use this when you need an immediate result and can wait for it.
```lua
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 string follows the pattern `namespace:name` where namespace identifies the module and name identifies the specific function.
## async
Starts an async function call and returns immediately with a Future. Use this for long-running operations where you don't want to block, or when you want to run multiple operations in parallel.
```lua
-- 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 payload, ok = ch:receive()
if ok then
local result = payload:data()
end
```
| Parameter | Type | Description |
|-----------|------|-------------|
| `target` | string | Function ID in format "namespace:name" |
| `...args` | any | Arguments passed to the function |
**Returns:** `Future, error`
## new
Creates a new Executor for building function calls with custom context. Use this when you need to propagate request context, set security credentials, or configure timeouts.
```lua
local exec = funcs.new()
```
**Returns:** `Executor, error`
## Executor
Builder for function calls with custom context options. Methods return new Executor instances (immutable chaining), so you can reuse a base configuration.
### with_context
Adds context values that will be available to the called function. Use this to propagate request-scoped data like trace IDs, user sessions, or feature flags.
```lua
-- Propagate request context to downstream services
local exec = funcs.new():with_context({
request_id = ctx.get("request_id"),
feature_flags = {dark_mode = true}
})
local user, err = exec:call("app.api:get_user", user_id)
```
| Parameter | Type | Description |
|-----------|------|-------------|
| `values` | table | Key-value pairs to add to context |
**Returns:** `Executor, error`
### with_actor
Sets the security actor for authorization checks in the called function. Use this when calling a function on behalf of a specific user.
```lua
local security = require("security")
local actor = security.actor() -- Get current user's actor
-- Call admin function with user's credentials
local exec = funcs.new():with_actor(actor)
local result, err = exec:call("app.admin:delete_record", record_id)
if err and err:kind() == "PERMISSION_DENIED" then
return nil, errors.new("PERMISSION_DENIED", "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. Scopes define the permissions available for the call.
```lua
local security = require("security")
local scope = security.new_scope()
local exec = funcs.new():with_scope(scope)
```
| Parameter | Type | Description |
|-----------|------|-------------|
| `scope` | Scope | Security scope (from security module) |
**Returns:** `Executor, error`
### with_options
Sets call options like timeout and priority. Use this for operations that need time limits.
```lua
-- Set a 5 second timeout for external API call
local exec = funcs.new():with_options({timeout = 5000})
local result, err = exec:call("app.external:fetch_data", query)
if err then
-- Handle timeout or other error
end
```
| Parameter | Type | Description |
|-----------|------|-------------|
| `options` | table | Implementation-specific options |
**Returns:** `Executor, error`
### call / async
Executor versions of call and async that use the configured context.
```lua
-- Build reusable executor with context
local exec = funcs.new()
:with_context({trace_id = "abc-123"})
:with_options({timeout = 10000})
-- Make multiple calls with same context
local users, _ = exec:call("app.api:list_users")
local posts, _ = exec:call("app.api:list_posts")
```
## Future
Returned by `async()` calls. Represents an in-progress async operation.
### response / channel
Returns the underlying channel for receiving the result.
```lua
local future, _ = funcs.async("app.api:slow_operation", data)
local ch = future:response() -- or future:channel()
local result = channel.select {
ch:case_receive(),
timeout:case_receive()
}
```
**Returns:** `Channel`
### is_complete
Non-blocking check if the future has completed.
```lua
while not future:is_complete() do
-- do other work
time.sleep("100ms")
end
local result, err = future:result()
```
**Returns:** `boolean`
### is_canceled
Returns true if `cancel()` was called on this future.
```lua
if future:is_canceled() then
print("Operation was canceled")
end
```
**Returns:** `boolean`
### result
Returns the cached result if complete, or nil if still pending.
```lua
local value, err = future:result()
if err then
print("Failed:", err:message())
elseif value then
print("Got:", value:data())
end
```
**Returns:** `Payload|nil, error|nil`
### error
Returns the error if the future failed.
```lua
local err, has_error = future:error()
if has_error then
print("Error kind:", err:kind())
end
```
**Returns:** `error|nil, boolean`
### cancel
Cancels the async operation.
```lua
future:cancel()
```
## Parallel Operations
Run multiple operations concurrently using async and channel.select.
```lua
-- Start multiple operations in parallel
local f1, _ = funcs.async("app.api:get_user", user_id)
local f2, _ = funcs.async("app.api:get_orders", user_id)
local f3, _ = funcs.async("app.api:get_preferences", user_id)
-- Wait for all to complete using channels
local user_ch = f1:channel()
local orders_ch = f2:channel()
local prefs_ch = f3:channel()
local results = {}
for i = 1, 3 do
local r = channel.select {
user_ch:case_receive(),
orders_ch:case_receive(),
prefs_ch:case_receive()
}
if r.channel == user_ch then
results.user = r.value:data()
elseif r.channel == orders_ch then
results.orders = r.value:data()
else
results.prefs = r.value:data()
end
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()` |
## 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 |
| Subscribe failed | `errors.INTERNAL` | no |
| Function error | varies | varies |
See [Error Handling](lua/core/errors.md) for working with errors.
## Navigation
Previous: Process (lua/core/process)
Next: Future (lua/core/future)