计算单元

Wippy 提供三种运行代码的方式:函数、进程和工作流。它们共享相同的底层机制,但在生存时间、状态存储位置以及失败时的处理方式上有所不同。

函数

函数是最简单的模型。你调用它们,它们运行,它们返回结果。调用之间不保持状态。

local result = funcs.call("app.math:add", 2, 3)

函数在调用者的上下文中执行。如果调用者取消或退出,任何正在运行的函数也会被取消。这让事情保持简单——你不必考虑清理。

将函数用于 HTTP 处理器、数据转换以及任何应该快速完成并返回结果的操作。

进程

进程是 Actor。它们跨多个消息维护状态,独立于启动它们的人运行,并通过消息传递进行通信。

local pid = process.spawn("app.workers:handler", "app:processes")
process.send(pid, "job", {task = "process_data"})

当你生成一个进程时,即使你的代码完成后它仍会继续运行。进程可以相互监控、链接在一起,并形成自动重启失败子进程的监管树。

调度器在工作线程池中多路复用数千个进程。每个进程在等待 I/O 时让出,让其他进程运行。

将进程用于后台作业、服务守护进程以及任何需要比其创建者存活更久或跨消息维护状态的情况。

工作流

工作流用于绝对不能失败的操作。它们将状态持久化到工作流提供者(Temporal 或其他),可以在崩溃、重启或基础设施变更后从中断处精确恢复。

-- 这可以运行数天,在重启后存活,永不丢失进度
workflow.execute("app.orders:process", order_id)

代价是延迟。每个步骤都会被记录,因此工作流比函数或进程慢。但对于多步骤业务流程或长时间运行的编排,这种持久性是值得的。

Wippy 自动处理工作流的确定性。你不需要学习任何特殊技术——编写普通代码,运行时确保它在重放期间行为正确。

比较

函数 进程 工作流
状态 内存中 持久化
生命周期 单次调用 直到退出或崩溃 能存活一切
通信 返回值 + 消息 消息传递 Activity 调用 + 消息
失败处理 调用者处理 监管树 自动重试
延迟 最低 较高

相同代码,不同行为

许多模块会自动适应其上下文。例如,函数中的 time.sleep() 阻塞工作线程,进程中它让出以让其他进程运行,而在工作流中它记录一个在恢复时正确重放的定时器。