Funciones

Las funciones son puntos de entrada de llamada y retorno. Una función hereda el contexto de su caller y se cancela cuando este se cancela. Los pools pueden reutilizar estados Lua, por lo que los globals de módulo y los upvalues de closures pueden sobrevivir en un worker, pero no se comparten de forma coherente entre llamadas. Guarda fuera de la función el estado durable o compartido. Usa funciones para handlers HTTP, endpoints de API y otras operaciones que terminen dentro del ciclo de vida de un request.

Llamar funciones

Llama funciones de forma síncrona con funcs.call():

local funcs = require("funcs")
local result, err = funcs.call("app.api:get_user", user_id)
if err then return nil, err end
return result

Para ejecución no bloqueante, usa funcs.async():

local future, err = funcs.async("app.process:analyze", data)
if err then
    return nil, err
end

local ch = future:response()
local payload, open = ch:receive()
if not open then
    return nil, "future response channel closed"
end

local result, err = payload:data()
if err then
    return nil, err
end

Consulta el módulo funcs para la invocación de funciones y las opciones del executor.

Propagación del contexto

Cada llamada crea un frame con su propio scope de contexto. Las funciones child heredan el contexto del parent sin pasarlo de forma explícita:

local ctx = require("ctx")

local trace_id = ctx.get("trace_id")
local user_id = ctx.get("user_id")

Añade contexto al llamar:

local funcs = require("funcs")

local exec, err = funcs.new():with_context({trace_id = "abc-123"})
if err then return nil, err end

local result, err = exec:call("app.api:process", data)
if err then return nil, err end
return result

El contexto de seguridad se propaga igual. Las funciones llamadas ven el actor del caller y pueden comprobar permisos. Consulta el módulo security para las API de control de acceso.

Definición en el registro

En el registro, una entrada de función tiene esta forma:

- name: get_user
  kind: function.lua
  source: file://handlers/user.lua
  method: get
  pool:
    type: lazy
    max_size: 16

Otros componentes del runtime pueden invocar funciones — handlers HTTP, queue consumers, scheduled jobs — y las llamadas están sujetas a comprobaciones de permisos basadas en el contexto de seguridad del caller.

Pools

Las funciones se ejecutan en pools que gestionan la ejecución. El tipo de pool determina el comportamiento de scaling.

Inline se ejecuta en la goroutine del caller sin un pool de workers. Se usa para contextos embebidos.

Static mantiene un número fijo de workers. Los requests esperan en queue cuando todos están ocupados, manteniendo fija la concurrencia.

pool:
  type: static
  size: 8
  buffer: 512

Lazy comienza sin workers y los crea bajo demanda. Los workers idle se eliminan tras un timeout.

pool:
  type: lazy
  max_size: 32

Adaptive ajusta el número de workers según el throughput medido y la carga actual.

pool:
  type: adaptive
  max_size: 256
Si no especifica un tipo de pool, el runtime selecciona uno basado en su configuración. Establezca `workers` para static, `max_size` para lazy, o establezca `type` explícitamente para control total. Si no se establece ninguno, el pool es lazy con un máximo de 16 workers.

Interceptors

Las llamadas a funciones pasan por una chain de interceptors. Estos pueden gestionar concerns transversales separados de la implementación de la función.

- name: my_function
  kind: function.lua
  source: file://handler.lua
  method: main
  meta:
    options:
      retry:
        max_attempts: 3
        initial_delay: 100
        backoff_factor: 2.0

Los interceptors integrados incluyen reintentos con exponential backoff. Las integraciones del runtime escritas en Go pueden registrar interceptors adicionales para logging, métricas, tracing, autorización, circuit breaking o transformación de requests; las entradas de aplicación Lua solo pueden configurar interceptors instalados por el runtime.

La chain se ejecuta antes y después de cada llamada. Cada interceptor puede modificar el request, cortocircuitar la ejecución o envolver la response.

Contratos

Las funciones pueden exponer sus schemas de entrada/salida como contratos. Los contratos definen signatures de métodos que permiten la validación en runtime y la generación de documentación.

local contract = require("contract")
local sender = contract.get("app.email:sender")
local email = sender:open("app.email:sender_impl")
email:send({to = "user@example.com", subject = "Hola"})

Los contratos permiten que los callers usen una interfaz mientras eligen por separado una implementación. Esto facilita pruebas, deployments multi-tenant y migraciones graduales.

Funciones frente a procesos

Las funciones heredan el contexto y ciclo de vida del caller. Cuando este se cancela, también se cancelan sus llamadas. Esto es adecuado para la ejecución dentro de handlers HTTP y queue consumers.

Los procesos se ejecutan independientemente con contexto del host. Sobreviven a su creador y se comunican mediante mensajes. Usa procesos para trabajo en segundo plano y funciones para operaciones con scope de request.