微软最近开源了一个 PostgreSQL 扩展——pg_durable,它的核心主张很简单:持久化工作流不需要再跑到外面去。工作流的状态、步骤、恢复逻辑全部在数据库内部完成,省掉 Temporal、Camunda 这类外部编排系统的一整套部署和维护成本。
为什么要把编排拉回数据库
传统做法里,一个业务流程(订单审批、退款处理、数据迁移)要跨多个服务调用,中间状态丢给外部编排引擎保管。这带来几个实际问题:
- 多了一层基础设施——编排引擎本身要集群、要存储、要监控,运维成本不低。
- 状态分散——业务数据在 PostgreSQL,流程状态在编排引擎的存储里,调试时要在两个系统之间来回跳。
- 网络开销——每一步都要从编排引擎发请求到业务服务,再写回状态,延迟和故障点都多了。
pg_durable 的思路是:既然业务数据已经在 PostgreSQL 里了,把流程状态也放进来,用数据库的事务和持久性保证工作流不会丢步、不会重复执行。
pg_durable 的核心机制
根据项目描述,pg_durable 在 PostgreSQL 内部实现了 durable execution——即工作流的每一步执行都是持久化的,遇到崩溃、重启后可以从断点恢复继续。关键设计点包括:
- 步骤级持久化:每个步骤完成后状态立即写入数据库,不依赖外部存储。
- 崩溃恢复:数据库重启后,未完成的工作流自动从上一个已完成步骤继续。
- SQL 可编程:工作流逻辑用 SQL 函数定义,不需要单独的 DSL 或 YAML 配置文件。
这意味着你不再需要为编排引擎单独搭建一套高可用集群——PostgreSQL 本身就是那个可靠的状态后端。
实际上手:定义并运行一个持久化工作流
下面演示如何安装扩展并创建一个简单的多步骤审批工作流。注意:部分 API 细节基于项目公开描述和合理推断,实际使用时请对照官方仓库确认。
安装扩展
# 从 GitHub 克隆并编译
git clone https://github.com/microsoft/pg_durable.git
cd pg_durable
# 编译安装(需要 pg_config 在 PATH 中)
make
make install
# 在目标数据库中启用扩展
psql -d your_db -c "CREATE EXTENSION pg_durable;"
定义一个退款审批工作流
假设业务场景:用户申请退款 → 自动风控检查 → 人工审批 → 执行退款。每一步都可能失败或超时,需要持久化保证。
-- 注册一个持久化工作流
SELECT pg_durable.register_workflow(
'refund_approval',
'process_refund_step'
);
-- 定义工作流的步骤函数
-- 每次被调用时根据当前步骤执行对应逻辑
CREATE OR REPLACE FUNCTION process_refund_step(
workflow_id UUID,
step_name TEXT,
input_data JSONB
) RETURNS JSONB AS $$
DECLARE
result JSONB;
BEGIN
CASE step_name
-- 第一步:风控自动检查
WHEN 'risk_check' THEN
-- 模拟风控逻辑:金额超过 5000 标记为需人工审核
IF (input_data->>'amount')::DECIMAL > 5000 THEN
result := jsonb_build_object(
'status', 'need_manual_review',
'next_step', 'manual_review'
);
ELSE
result := jsonb_build_object(
'status', 'auto_approved',
'next_step', 'execute_refund'
);
END IF;
-- 第二步:人工审批(此处仅标记等待状态,实际可对接审批系统回调)
WHEN 'manual_review' THEN
result := jsonb_build_object(
'status', 'pending_approval',
'next_step', 'execute_refund',
'note', '等待审批人操作'
);
-- 第三步:执行退款
WHEN 'execute_refund' THEN
-- 在事务中完成退款并更新订单状态
UPDATE orders
SET refund_status = 'completed',
refunded_at = now()
WHERE order_id = (input_data->>'order_id')::INT;
result := jsonb_build_object(
'status', 'done',
'next_step', NULL -- NULL 表示工作流结束
);
ELSE
RAISE EXCEPTION '未知步骤: %', step_name;
END CASE;
RETURN result;
END;
$$ LANGUAGE plpgsql;
启动一个工作流实例
-- 发起一笔退款审批
SELECT pg_durable.start_workflow(
'refund_approval',
jsonb_build_object(
'order_id', 1024,
'amount', 3200,
'user_id', 887
)
);
查询工作流状态
-- 查看所有进行中的退款工作流
SELECT workflow_id, current_step, status, created_at
FROM pg_durable.workflow_instances
WHERE workflow_name = 'refund_approval'
AND status != 'done'
ORDER BY created_at;
如果 PostgreSQL 在风控检查完成后崩溃重启,pg_durable 会从已持久化的 risk_check 结果恢复,直接进入下一步,不会重复执行风控逻辑——这正是 durable execution 的核心价值。
什么时候该用,什么时候不该用
适合的场景:
- 工作流步骤本身就是数据库操作(状态更新、数据迁移、批量计算),编排和数据在同一个地方最自然。
- 团队已经深度使用 PostgreSQL,不想再引入一套独立的编排基础设施。
- 流程步骤数量有限(几十步以内),不需要跨数十个微服务的复杂拓扑。
需要谨慎的场景:
- 工作流需要调用大量外部 HTTP 服务——把所有外部调用塞进 PostgreSQL 函数会让数据库承担不该承担的网络职责,此时外部编排引擎更合适。
- 流程涉及长时间等待(数天、数周的人工审批),数据库连接和事务不宜长期持有,需要确认
pg_durable的等待机制是否适合你的场景。 - 已有成熟的 Temporal / Camunda 部署和运维体系,迁移成本需要认真评估。
上手建议
- 先在非生产环境试跑——克隆仓库、编译安装、跑通上面的退款示例,感受步骤恢复的实际行为。
- 对照现有编排方案做成本估算——如果你目前用 Temporal,算一算去掉那套集群后省了多少机器和运维时间;如果流程复杂度不高,收益可能很直接。
- 关注扩展的成熟度——这是微软刚开源的项目,API 和稳定性还在演进中,生产使用前务必跟踪 issue 和版本更新。
- 从简单流程开始替换——挑一个三五步的内部流程(比如数据清洗、状态机流转)先用
pg_durable实现,验证崩溃恢复和监控是否满足要求,再考虑更大范围采用。
持久化工作流进数据库,本质上是在用 PostgreSQL 已经很成熟的事务和恢复能力,替代编排引擎专门建的那一层。对很多中等复杂度的业务流程来说,这可能是更务实的选择。