Invocação de Funções
A forma principal de chamar outras funções no Wippy. Execute funções registradas síncronamente ou assíncronamente entre processos, com suporte completo para propagação de contexto, credenciais de segurança e timeouts. Este módulo é central para construir aplicações distribuídas onde componentes precisam comunicar.
Carregamento
local funcs = require("funcs")
call
Chama uma função registrada síncronamente. Use quando precisar de um resultado imediato e puder aguardar por ele.
local result, err = funcs.call("app.api:get_user", user_id)
if err then
return nil, err
end
print(result.name)
| Parâmetro | Tipo | Descrição |
|---|---|---|
target |
string | ID da função no formato "namespace:name" |
...args |
any | Argumentos passados para a função |
Retorna: result, error
A string target segue o padrão namespace:name onde namespace identifica o módulo e name identifica a função específica.
async
Inicia uma chamada de função assíncrona e retorna imediatamente com um Future. Use para operações de longa duração onde você não quer bloquear, ou quando quer executar múltiplas operações em paralelo.
-- Iniciar computação pesada sem bloquear
local future, err = funcs.async("app.process:analyze_data", large_dataset)
if err then
return nil, err
end
-- Fazer outro trabalho enquanto computação executa...
-- Aguardar resultado quando pronto
local ch = future:response()
local payload, ok = ch:receive()
if ok then
local result = payload:data()
end
| Parâmetro | Tipo | Descrição |
|---|---|---|
target |
string | ID da função no formato "namespace:name" |
...args |
any | Argumentos passados para a função |
Retorna: Future, error
new
Cria um novo Executor para construir chamadas de função com contexto customizado. Use quando precisar propagar contexto de requisição, definir credenciais de segurança ou configurar timeouts.
local exec = funcs.new()
Retorna: Executor, error
Executor
Builder para chamadas de função com opções de contexto customizado. Métodos retornam novas instâncias de Executor (encadeamento imutável), então você pode reutilizar uma configuração base.
with_context
Adiciona valores de contexto que estarão disponíveis para a função chamada. Use para propagar dados com escopo de requisição como trace IDs, sessões de usuário ou feature flags.
-- Propagar contexto de requisição para serviços downstream
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)
| Parâmetro | Tipo | Descrição |
|---|---|---|
values |
table | Pares chave-valor para adicionar ao contexto |
Retorna: Executor, error
with_actor
Define o ator de segurança para verificações de autorização na função chamada. Use ao chamar uma função em nome de um usuário específico.
local security = require("security")
local actor = security.actor() -- Obter ator do usuário atual
-- Chamar função admin com credenciais do usuário
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
| Parâmetro | Tipo | Descrição |
|---|---|---|
actor |
Actor | Ator de segurança (do módulo security) |
Retorna: Executor, error
with_scope
Define o escopo de segurança para funções chamadas. Escopos definem as permissões disponíveis para a chamada.
local security = require("security")
local scope = security.new_scope()
local exec = funcs.new():with_scope(scope)
| Parâmetro | Tipo | Descrição |
|---|---|---|
scope |
Scope | Escopo de segurança (do módulo security) |
Retorna: Executor, error
with_options
Define opções de chamada como timeout e prioridade. Use para operações que precisam de limites de tempo.
-- Definir timeout de 5 segundos para chamada de API externa
local exec = funcs.new():with_options({timeout = 5000})
local result, err = exec:call("app.external:fetch_data", query)
if err then
-- Tratar timeout ou outro erro
end
| Parâmetro | Tipo | Descrição |
|---|---|---|
options |
table | Opções específicas da implementação |
Retorna: Executor, error
call / async
Versões Executor de call e async que usam o contexto configurado.
-- Construir executor reutilizável com contexto
local exec = funcs.new()
:with_context({trace_id = "abc-123"})
:with_options({timeout = 10000})
-- Fazer multiplas chamadas com mesmo contexto
local users, _ = exec:call("app.api:list_users")
local posts, _ = exec:call("app.api:list_posts")
Future
Retornado por chamadas async(). Representa uma operação assíncrona em andamento.
response / channel
Retorna o channel subjacente para receber o resultado.
local future, _ = funcs.async("app.api:slow_operation", data)
local ch = future:response() -- ou future:channel()
local result = channel.select {
ch:case_receive(),
timeout:case_receive()
}
Retorna: Channel
is_complete
Verificação não-bloqueante se o future completou.
while not future:is_complete() do
-- fazer outro trabalho
time.sleep("100ms")
end
local result, err = future:result()
Retorna: boolean
is_canceled
Retorna true se cancel() foi chamado neste future.
if future:is_canceled() then
print("Operation was canceled")
end
Retorna: boolean
result
Retorna o resultado em cache se completo, ou nil se ainda pendente.
local value, err = future:result()
if err then
print("Failed:", err:message())
elseif value then
print("Got:", value:data())
end
Retorna: Payload|nil, error|nil
error
Retorna o erro se o future falhou.
local err, has_error = future:error()
if has_error then
print("Error kind:", err:kind())
end
Retorna: error|nil, boolean
cancel
Cancela a operação assíncrona.
future:cancel()
Operações Paralelas
Execute múltiplas operações concorrentemente usando async e channel.select.
-- Iniciar múltiplas operações em paralelo
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)
-- Aguardar todas completarem usando 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
Permissões
Operações de função estão sujeitas a avaliação de política de segurança.
| Ação | Recurso | Descrição |
|---|---|---|
funcs.call |
ID da Função | Chamar uma função específica |
funcs.context |
context |
Usar with_context() para definir contexto customizado |
funcs.security |
security |
Usar with_actor() ou with_scope() |
Erros
| Condição | Tipo | Retentável |
|---|---|---|
| Target vazio | errors.INVALID |
não |
| Namespace ausente | errors.INVALID |
não |
| Nome ausente | errors.INVALID |
não |
| Permissão negada | errors.PERMISSION_DENIED |
não |
| Falha de inscrição | errors.INTERNAL |
não |
| Erro da função | varia | varia |
Veja Error Handling para trabalhar com erros.