跳转到内容

函数调用

在 Wippy 中调用其他函数的主要方式。跨进程同步或异步执行已注册的函数,完全支持上下文传播、安全凭证和超时。此模块是构建需要组件间通信的分布式应用的核心。

local funcs = require("funcs")

同步调用已注册的函数。当需要立即获取结果并可以等待时使用。

local result, err = funcs.call("app.api:get_user", user_id)
if err then
return nil, err
end
print(result.name)
参数类型描述
targetstring函数 ID,格式为 “namespace:name”
...argsany传递给函数的参数

返回: result, error

目标字符串遵循 namespace:name 模式,namespace 标识模块,name 标识具体函数。

启动异步函数调用并立即返回 Future。用于不想阻塞的长时间运行操作,或想并行运行多个操作时。

-- 启动耗时计算而不阻塞
local future, err = funcs.async("app.process:analyze_data", large_dataset)
if err then
return nil, err
end
-- 计算运行期间做其他工作...
-- 准备好时等待结果
local ch = future:response()
local payload, ok = ch:receive()
if ok then
local result = payload:data()
end
参数类型描述
targetstring函数 ID,格式为 “namespace:name”
...argsany传递给函数的参数

返回: Future, error

创建带自定义上下文的 Executor 用于构建函数调用。当需要传播请求上下文、设置安全凭证或配置超时时使用。

local exec = funcs.new()

返回: Executor

带自定义上下文选项的函数调用构建器。方法返回新的 Executor 实例(不可变链式调用),因此可以复用基础配置。

添加将对被调用函数可用的上下文值。用于传播请求作用域数据,如跟踪 ID、用户会话或功能标志。

-- 向下游服务传播请求上下文
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)
参数类型描述
valuestable要添加到上下文的键值对

返回: Executor, error

设置被调用函数中授权检查的安全 actor。代表特定用户调用函数时使用。

local security = require("security")
local actor = security.actor() -- 获取当前用户的 actor
-- 用用户凭证调用管理函数
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
参数类型描述
actorActor安全 actor(来自 security 模块)

返回: Executor, error

设置被调用函数的安全作用域。作用域定义调用可用的权限。

local security = require("security")
local scope = security.new_scope()
local exec = funcs.new():with_scope(scope)
参数类型描述
scopeScope安全作用域(来自 security 模块)

返回: Executor, error

设置调用选项如超时和优先级。用于需要时间限制的操作。

-- 为外部 API 调用设置 5 秒超时
local exec = funcs.new():with_options({timeout = 5000})
local result, err = exec:call("app.external:fetch_data", query)
if err then
-- 处理超时或其他错误
end
参数类型描述
optionstable实现特定选项

返回: Executor, error

使用配置的上下文的 Executor 版本的 call 和 async。

-- 构建带上下文的可复用 executor
local exec = funcs.new()
:with_context({trace_id = "abc-123"})
:with_options({timeout = 10000})
-- 使用相同上下文进行多次调用
local users, _ = exec:call("app.api:list_users")
local posts, _ = exec:call("app.api:list_posts")

async() 调用返回。表示进行中的异步操作。

返回用于接收结果的底层通道。

local future, _ = funcs.async("app.api:slow_operation", data)
local ch = future:response() -- 或 future:channel()
local result = channel.select {
ch:case_receive(),
timeout:case_receive()
}

返回: Channel

非阻塞检查 future 是否已完成。

while not future:is_complete() do
-- 做其他工作
time.sleep("100ms")
end
local result, err = future:result()

返回: boolean

返回是否对此 future 调用了 cancel()

if future:is_canceled() then
print("Operation was canceled")
end

返回: boolean

返回缓存的结果(若已完成),或仍在等待时返回 nil。

local value, err = future:result()
if err then
print("Failed:", err:message())
elseif value then
print("Got:", value:data())
end

返回: Payload|nil, error|nil

返回 future 失败时的错误。

local err, has_error = future:error()
if has_error then
print("Error kind:", err:kind())
end

返回: error|nil, boolean

取消异步操作。

future:cancel()

返回: boolean, error

使用 async 和 channel.select 并发运行多个操作。

-- 并行启动多个操作
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)
-- 使用通道等待全部完成
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

函数操作受安全策略评估约束。

动作资源描述
funcs.call函数 ID调用特定函数
funcs.contextcontext使用 with_context() 设置自定义上下文
funcs.securitysecurity使用 with_actor()with_scope()
条件类型可重试
目标为空errors.INVALID
缺少命名空间errors.INVALID
缺少名称errors.INVALID
权限被拒绝errors.PERMISSION_DENIED
订阅失败errors.INTERNAL
函数错误各异各异

参见 错误处理 了解错误处理方法。