入口类型参考

Wippy 中所有可用入口类型的完整参考。

入口之间使用 namespace:name 格式相互引用。注册表根据这些引用自动连接依赖关系,确保资源按正确顺序初始化。

参见

Lua 运行时

类型 说明
function.lua Lua 函数入口点
process.lua 长期运行的 Lua 进程
workflow.lua Temporal 工作流(确定性)
library.lua 共享 Lua 库
module.lua Lua 模块接口
function.lua.bc 预编译函数字节码
library.lua.bc 预编译库字节码
process.lua.bc 预编译进程字节码
workflow.lua.bc 预编译工作流字节码
- name: handler
  kind: function.lua
  source: file://handler.lua
  method: main
  modules:
    - http
    - json
  imports:
    utils: app.lib:helpers  # 将另一个入口作为模块导入
使用 imports 引用其他 Lua 入口。它们在代码中可通过 require("alias_name") 使用。

HTTP 服务

类型 说明
http.service HTTP 服务器(绑定端口)
http.router 路由前缀和中间件
http.endpoint HTTP 端点(方法 + 路径)
http.static 静态文件服务
# HTTP 服务器
- name: gateway
  kind: http.service
  addr: ":8080"
  lifecycle:
    auto_start: true

# 带中间件的路由
- name: api
  kind: http.router
  meta:
    server: gateway
  prefix: /api
  middleware:
    - cors
    - ratelimit

# 端点
- name: users_list
  kind: http.endpoint
  meta:
    router: app:api
  method: GET
  path: /users
  func: list_handler

Lua API: 参见 HTTP 模块

local http = require("http")
local req = http.request()
local resp = http.response()

resp:set_status(200)
resp:write_json({users = get_users()})

数据库

类型 说明
db.sql.sqlite SQLite 数据库
db.sql.postgres PostgreSQL 数据库
db.sql.mysql MySQL 数据库
db.cdc.postgres Postgres 变更数据捕获源(参见 CDC)
db.cdc.sqlite SQLite 变更数据捕获源(参见 CDC)

SQLite

- name: database
  kind: db.sql.sqlite
  file: "./data/app.db"
  lifecycle:
    auto_start: true

# 用于测试的内存数据库
- name: testdb
  kind: db.sql.sqlite
  file: ":memory:"

PostgreSQL

- name: database
  kind: db.sql.postgres
  host: localhost
  port: 5432
  database: dbname
  username: user
  password: pass
  options:
    sslmode: disable
  pool:
    max_open: 25
    max_idle: 5
    max_lifetime: "30m"
  lifecycle:
    auto_start: true

MySQL

- name: database
  kind: db.sql.mysql
  host: localhost
  port: 3306
  database: dbname
  username: user
  password: pass
  options:
    parseTime: "true"
  lifecycle:
    auto_start: true

参见 Database 了解 ${env:NAME} 密钥引用、TLS 选项和连接池调优。当数据库条目背后由 env 支持的值发生变化时,连接池会实时切换 — 活跃的借用连接会在旧连接设置下完成。

Lua API: 参见 SQL 模块

local sql = require("sql")
local db, err = sql.get("app:database")

local rows, err = db:query("SELECT * FROM users WHERE id = ?", user_id)
db:execute("INSERT INTO logs (msg) VALUES (?)", message)

键值存储

类型 说明
store.memory 内存键值存储
store.sql SQL 后端键值存储
store.kv.raft 集群复制、强一致性 KV(共享 Raft)
store.kv.crdt 集群复制、最终一致性 KV(gossip/CRDT)
# 内存存储
- name: cache
  kind: store.memory
  lifecycle:
    auto_start: true

# SQL 后端存储
- name: persistent_store
  kind: store.sql
  database: app:database
  table_name: kv_store
  lifecycle:
    auto_start: true

# 集群复制存储(需要启用集群)
- name: deployments
  kind: store.kv.raft
  namespace: deploy

store.kv.* 类型需要启用集群。一致性权衡参见 Store。

Lua API: 参见 Store 模块

local store = require("store")
local s, err = store.get("app:cache")

s:set("user:123", user_data, 3600)  -- TTL 单位为秒
local data = s:get("user:123")

队列

类型 说明
queue.driver.memory 内存队列驱动
queue.driver.amqp AMQP (RabbitMQ) 驱动
queue.driver.sqs AWS SQS 驱动
queue.queue 队列声明
queue.consumer 队列消费者
# 驱动
- name: queue_driver
  kind: queue.driver.memory
  lifecycle:
    auto_start: true

# 队列
- name: jobs
  kind: queue.queue
  driver: queue_driver

# 消费者
- name: job_consumer
  kind: queue.consumer
  queue: app:jobs
  func: job_handler
  concurrency: 4
  prefetch: 10
  lifecycle:
    auto_start: true

Lua API: 参见 Queue 模块

local queue = require("queue")

-- 发布消息
queue.publish("app:jobs", {task = "process", id = 123})

-- 在消费者处理函数中:消息体就是处理函数的参数
local function main(data)
    -- 通过当前消息访问投递元数据
    local msg = queue.message()
    local id = msg:id()
    local priority = msg:header("priority")
    msg:ack()
end
消费者的 func 每收到一条消息就被调用一次,消息体作为其参数。在处理函数中使用 queue.message() 获取该次投递的 id()、header()/headers() 和 ack()/nack()。

进程管理

类型 说明
process.host 进程执行宿主
process.service 受监督的进程(包装 process.lua)
terminal.host 终端/CLI 宿主
pg.scope 进程组作用域(参见 进程组)
# 进程宿主(进程运行的地方)
- name: processes
  kind: process.host
  host:
    workers: 32             # 工作 goroutine 数(默认:NumCPU)
    queue_size: 1024        # 全局队列容量
    local_queue_size: 256   # 每个工作线程的队列
  lifecycle:
    auto_start: true

# 进程定义
- name: worker_process
  kind: process.lua
  source: file://worker.lua
  method: main

# 受监督的进程服务
- name: worker
  kind: process.service
  process: app:worker_process
  host: app:processes
  input: ["arg1", "arg2"]
  lifecycle:
    auto_start: true
    restart:
      max_attempts: 10

- name: terminal
  kind: terminal.host
  lifecycle:
    auto_start: true
当需要将进程作为具有自动重启功能的受监督服务运行时,使用 process.service。process 字段引用一个 process.lua 入口。

实时更新 process.host 条目会就地重设 host.workers 的规模 — 运行中的进程、PID 和队列都会保留。host.queue_size、host.local_queue_size 和 lifecycle 在构造时固定:实时更新更改它们会被拒绝;对 worker 采用亲和性管理的宿主调整 worker 数量同样会被拒绝。

进程安全

process.lua 和 process.lua.bc 条目接受一个顶层 security: 块。它属于条目本身,因此对该进程的每次 spawn 都生效,在 process.host 和 terminal.host 上都是如此:

- name: worker_process
  kind: process.lua
  source: file://worker.lua
  method: main
  security:
    actor:
      id: system.worker
      meta:
        tenant: acme
    policies:
      - app.security:worker_policy
    groups:
      - app.security:background_jobs
字段 说明
actor.id 进程运行时所用的主体身份;替换继承来的主体
actor.meta 供策略求值的主体属性
policies 合并进作用域的策略的注册表 ID(namespace:name)
groups 其策略被合并进作用域的策略组的注册表 ID

解析在进程启动时进行且是原子的:只要所列的任一策略或组无法解析,spawn 就会失败,并且不会安装任何不完整的上下文。省略 actor 会继承 spawn 发起方的主体;同时省略 policies 和 groups 会继承 spawn 发起方的作用域。function.lua、function.lua.bc、process.lua 和 process.lua.bc 都接受该块。

命令条目还可以额外声明 meta.command.security,它只在该条目作为 CLI 命令启动时生效——参见命令安全。它不影响普通的 spawn。

参见 安全。

Temporal(工作流)

类型 说明
temporal.client Temporal 客户端连接
temporal.worker Temporal 工作线程
- name: temporal_client
  kind: temporal.client
  address: "localhost:7233"
  namespace: "default"
  auth:
    type: none  # none, api_key, mtls
  lifecycle:
    auto_start: true

- name: temporal_worker
  kind: temporal.worker
  client: temporal_client
  task_queue: "main-queue"
  lifecycle:
    auto_start: true

云存储

类型 说明
config.aws AWS 配置
cloudstorage.s3 S3 存储桶访问
- name: aws
  kind: config.aws
  region: "us-east-1"
  access_key_id: ${env:AWS_ACCESS_KEY_ID}
  secret_access_key: ${env:AWS_SECRET_ACCESS_KEY}

- name: uploads
  kind: cloudstorage.s3
  config: app:aws
  bucket: "my-uploads"
  endpoint: ""  # 可选,用于 S3 兼容服务

Lua API: 参见 Cloud Storage 模块

local cloudstorage = require("cloudstorage")
local storage, err = cloudstorage.get("app:uploads")

storage:upload_object("files/doc.pdf", file_content)
local url = storage:presigned_get_url("files/doc.pdf", {expiration = 3600})  -- 单位为秒,默认 3600
使用 endpoint 连接 S3 兼容服务,如 MinIO 或 DigitalOcean Spaces。

文件系统

类型 说明
fs.directory 目录访问
fs.embed 只读嵌入式文件系统
- name: data_dir
  kind: fs.directory
  directory: "./data"
  auto_init: true   # 不存在时创建
  mode: "0755"      # 权限

Lua API: 参见 Filesystem 模块

local fs = require("fs")
local filesystem, err = fs.get("app:data_dir")

local file = filesystem:open("output.txt", "w")
file:write("Hello, World!")
file:close()

环境

类型 说明
env.storage.memory 内存环境存储
env.storage.file 文件环境存储
env.storage.os 操作系统环境
env.storage.static 只读静态键值存储
env.storage.router 环境路由(多存储)
env.variable 环境变量
- name: os_env
  kind: env.storage.os

- name: file_env
  kind: env.storage.file
  file_path: ".env"
  auto_create: true

- name: defaults
  kind: env.storage.static
  values:
    PUBLIC_API_HOST: "https://api.example.com"
    APP_ENV: "production"

- name: app_env
  kind: env.storage.router
  storages:
    - app:os_env
    - app:file_env
    - app:defaults

Lua API: 参见 Env 模块

local env = require("env")

local api_key = env.get("API_KEY")
env.set("CACHE_TTL", "3600")
路由器按顺序尝试存储。读取时返回第一个匹配的结果;写入时使用列表中的第一个存储。

模板

类型 说明
template.jet 单个 Jet 模板
template.set 模板集配置
# 带引擎配置的模板集
- name: templates
  kind: template.set
  engine:
    development_mode: false
    extensions:
      - ".jet"
      - ".html.jet"

# 单个模板
- name: email_template
  kind: template.jet
  source: file://templates/email.jet
  set: app:templates

Lua API: 参见 Template 模块

local templates = require("templates")
local set, err = templates.get("app:templates")

local html = set:render("email", {
    user = "Alice",
    message = "Welcome!"
})

安全

类型 说明
security.policy 带条件的安全策略
security.policy.expr 基于表达式的策略
security.token_store 令牌存储
# 基于条件的策略
- name: admin_policy
  kind: security.policy
  policy:
    actions: "*"
    resources: "*"
    effect: allow
    conditions:
      - field: "actor.meta.role"
        operator: eq
        value: "admin"

# 基于表达式的策略
- name: owner_policy
  kind: security.policy.expr
  policy:
    actions: "*"
    resources: "*"
    effect: allow
    expression: 'actor.id == meta.owner_id || actor.meta.role == "admin"'
  groups:
    - operators

策略组由策略自身构成:策略在 groups: 下列出它所属的组 ID,而一个组就是指定了该组的策略集合。不存在单独的组条目类型。组 ID 是注册表 ID——裸名称在声明该策略的命名空间中解析,因此上面的 operators 在命名空间 app.security 中声明时就是 app.security:operators。条目通过完整的 namespace:name 引用组。

Lua API: 参见 Security 模块

local security = require("security")

-- 操作前检查权限
if security.can("delete", "users", {user_id = id}) then
    delete_user(id)
end

-- 获取当前角色
local actor = security.actor()
作用域内的每条策略都会被评估。任何匹配策略的 deny 都优先于所有 allow;若没有 deny,则匹配的 allow 授予访问权限。顺序无关紧要。

契约(依赖注入)

类型 说明
contract.definition 带方法规范的接口
contract.binding 将契约方法映射到函数实现
# 定义契约接口
- name: greeter
  kind: contract.definition
  methods:
    - name: greet
      description: Returns a greeting message
    - name: greet_with_name
      description: Returns a personalized greeting
      input_schemas:
        - format: "application/schema+json"
          definition: {"type": "string"}
      output_schemas:
        - format: "application/schema+json"
          definition: {"type": "string"}

# 实现函数
- name: greeter_greet
  kind: function.lua
  source: file://greeter_greet.lua
  method: main

- name: greeter_greet_name
  kind: function.lua
  source: file://greeter_greet_name.lua
  method: main

# 将契约方法绑定到实现
- name: greeter_impl
  kind: contract.binding
  contracts:
    - contract: app:greeter
      default: true
      methods:
        greet: app:greeter_greet
        greet_with_name: app:greeter_greet_name

在 Lua 中使用:

local contract = require("contract")

-- 通过 ID 打开绑定
local greeter, err = contract.open("app:greeter_impl")

-- 调用方法
local result = greeter:greet()
local personalized = greeter:greet_with_name("Alice")

-- 检查实例是否实现了契约
local is_greeter = contract.is(greeter, "app:greeter")

Lua API: 参见 Contract 模块

将一个绑定标记为 default: true,可在不指定绑定 ID 的情况下打开契约。一个契约只能有一个默认绑定。

执行

类型 说明
exec.native 原生命令执行
exec.docker Docker 容器执行
- name: native_exec
  kind: exec.native
  default_work_dir: "/app"
  command_whitelist:
    - "ls"
    - "cat"

- name: docker_exec
  kind: exec.docker
  image: "python:3.11-slim"
  default_work_dir: "/workspace"
  auto_remove: true
  memory_limit: 536870912  # 512MB
  command_whitelist:
    - "python"

WASM 运行时

类型 说明
function.wat WebAssembly 函数(WAT 文本格式)
function.wasm WebAssembly 函数(二进制)
process.wasm WebAssembly 进程
# WAT 文本作为内联源码
- name: sum_wat
  kind: function.wat
  source: file://sum.wat
  method: sum
  transport: payload   # 或 wasi-http

# 二进制 WASM 从文件系统条目加载,并通过哈希校验
- name: sum
  kind: function.wasm
  fs: app:modules
  path: sum.wasm
  hash: sha256:2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae
  method: sum
  transport: payload

function.wasm 和 process.wasm 接受 fs、path 和 hash——二进制条目上没有 source 字段;source 只属于 function.wat。hash 是必填的,且必须为 sha256:<hex>;字节不匹配时模块会被拒绝。

参见 WASM 概述。

网络

类型 说明
network 基础网络叠加层
network.socks5 SOCKS5 代理叠加层
network.i2p I2P 网络叠加层
network.tailscale Tailscale 叠加层

由 http.service 通过 network: 引用,由 funcs/process 通过 network 选项引用,由 http_client 通过 overlay_network 选项引用。参见 网络。

注册表原语

类型 说明
registry.entry 背后没有服务的纯数据条目(应用特定配置)
ns.definition 命名空间定义
ns.requirement 命名空间需求声明
ns.dependency 命名空间依赖

ns.* 类型和其他条目一样由作者编写:组件声明 ns.definition 和 ns.requirement,宿主声明 ns.dependency。参见构建组件。

生命周期配置

大多数入口支持生命周期配置:

- name: service
  kind: some.kind
  lifecycle:
    auto_start: true          # 自动启动
    start_timeout: 10s        # 最大启动时间
    stop_timeout: 10s         # 最大关闭时间
    stable_threshold: 5s      # 视为稳定的运行时间
    depends_on:
      - app:database
    restart:                  # 重试策略
      initial_delay: 1s
      max_delay: 90s
      backoff_factor: 2.0
      max_attempts: 0         # 0 = 无限
使用 depends_on 确保入口按正确顺序启动。只有在每个依赖项各自完成启动之后,监督器才会启动依赖它们的入口。

入口引用格式

入口使用 namespace:name 格式引用:

# 定义
namespace: app.users
entries:
  - name: handler
    kind: function.lua

# 从另一个入口引用
func: app.users:handler

覆盖入口 {id="overriding-entries"}

任何入口的字段——包括其 kind——都可以在启动时覆盖,无需编辑源 YAML,使用 override: 配置区段或 -o CLI 参数。键采用 namespace:entry:path 格式:

override:
  app:gateway:addr: ":9090"        # data field (a bare path targets data.*)
  app:worker:meta.priority: high    # meta field
  app:db:kind: db.sql.postgres      # the entry's typed kind
  app:db:data.kind: custom          # a payload field literally named "kind"
路径 目标
kind 入口的类型化 kind(必须是非空字符串)
data.<field> 或裸 <field> 入口 data 负载中的字段
meta.<field> 入口元数据中的字段

同样的覆盖也可从 CLI 应用:

wippy run -o app:db:kind=db.sql.postgres -o app:gateway:addr=:9090

CLI(-o)值按形态强制转换(true/false 转为 bool,数字转为数字,其他转为 string);override: 区段的值保留其 YAML 类型。如需覆盖全局配置区段而非入口,请使用 --set。