首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >业务流:从流程建模到可执行引擎的工程实践

业务流:从流程建模到可执行引擎的工程实践

原创
作者头像
用户12339161
发布于 2026-10-12 17:51:47
发布于 2026-10-12 17:51:47
1000
举报

业务流(Business Process)是企业系统的骨架。订单从创建到履约、工单从提交到关闭、审批从发起到归档——每一条业务流背后,都是状态、规则、参与者与异常处理的复杂交织。专业做法不是把逻辑散落在 Service 里,而是把流程抽象为可建模、可执行、可观测的引擎。本文从状态机建模、编排引擎、异常补偿、可观测性四个维度,给出可落地的架构与代码。

一、流程建模:状态机是基础

业务流的第一性原理是状态机。任何流程都可以拆解为:状态集合、事件集合、转移规则、动作。以订单履约为例:

text

代码语言:javascript
复制
待支付 → 已支付 → 配货中 → 已发货 → 已签收
   ↓        ↓        ↓        ↓
 已取消   已退款   异常待处理  退货中

用代码定义状态与转移:

代码语言:javascript
复制
public enum OrderState {
    PENDING_PAYMENT, PAID, PICKING, SHIPPED,
    DELIVERED, CANCELLED, REFUNDED, EXCEPTION
}

public enum OrderEvent {
    PAY, CANCEL, PICK, SHIP, DELIVER, REFUND, EXCEPTION
}

public class OrderStateMachine {
    private static final Map<OrderState, Map<OrderEvent, OrderState>> TRANSITIONS =
        Map.of(
            OrderState.PENDING_PAYMENT, Map.of(
                OrderEvent.PAY, OrderState.PAID,
                OrderEvent.CANCEL, OrderState.CANCELLED),
            OrderState.PAID, Map.of(
                OrderEvent.PICK, OrderState.PICKING,
                OrderEvent.REFUND, OrderState.REFUNDED),
            OrderState.PICKING, Map.of(
                OrderEvent.SHIP, OrderState.SHIPPED,
                OrderEvent.EXCEPTION, OrderState.EXCEPTION),
            OrderState.SHIPPED, Map.of(
                OrderEvent.DELIVER, OrderState.DELIVERED)
        );

    public OrderState next(OrderState current, OrderEvent event) {
        var transitions = TRANSITIONS.getOrDefault(current, Map.of());
        var next = transitions.get(event);
        if (next == null) {
            throw new IllegalStateException(
                "非法转移: " + current + " + " + event);
        }
        return next;
    }
}

关键点:转移规则是数据,不是 if-else 堆砌。这使流程可配置、可测试、可审计。

二、编排引擎:事件驱动与持久化

状态机定义了"能怎么走",编排引擎负责"实际怎么走"。核心要求:事件驱动、状态持久化、幂等执行。

代码语言:javascript
复制
public record OrderContext(
    String orderId, OrderState state,
    Map<String, Object> data, List<String> audit) {}

public interface OrderRepository {
    OrderContext load(String orderId);
    void save(OrderContext ctx);
    boolean tryLock(String orderId, String token);
}

@Service
public class OrderFlowEngine {
    private final OrderStateMachine machine;
    private final OrderRepository repo;
    private final ApplicationEventPublisher publisher;

    public OrderContext fire(String orderId, OrderEvent event) {
        String lockToken = UUID.randomUUID().toString();
        if (!repo.tryLock(orderId, lockToken)) {
            throw new ConcurrentModificationException("流程正在处理中");
        }
        try {
            OrderContext ctx = repo.load(orderId);
            OrderState next = machine.next(ctx.state(), event);
            OrderContext updated = new OrderContext(
                ctx.orderId(), next, ctx.data(),
                append(ctx.audit(), ctx.state() + "->" + next)
            );
            repo.save(updated);
            publisher.publishEvent(new StateChangedEvent(orderId, next));
            return updated;
        } finally {
            repo.unlock(orderId, lockToken);
        }
    }
}

这里用乐观锁防止并发重复推进,用事件发布解耦后续动作。订单状态变更后,发货、通知、积分等逻辑通过监听事件异步执行,不阻塞主流程。

三、异常补偿:Saga 模式

长流程必然有中间状态。订单已支付但库存扣减失败怎么办?答案是 Saga 模式——每个正向操作配一个补偿操作,失败时反向执行。

代码语言:javascript
复制
public record FlowStep(
    String name,
    Runnable action,
    Runnable compensate) {}

public class OrderSaga {
    private final Deque<FlowStep> executed = new ArrayDeque<>();
    private final AuditLogger audit;

    public void execute(List<FlowStep> steps) {
        try {
            for (FlowStep step : steps) {
                step.action().run();
                executed.push(step);
                audit.log(step.name(), "ok");
            }
        } catch (Exception e) {
            audit.log("saga", "rollback triggered: " + e.getMessage());
            while (!executed.isEmpty()) {
                FlowStep step = executed.pop();
                try {
                    step.compensate().run();
                    audit.log(step.name(), "compensated");
                } catch (Exception ce) {
                    audit.log(step.name(), "compensate failed: " + ce.getMessage());
                    // 补偿失败必须告警,转人工
                }
            }
            throw new FlowException("Saga 回滚完成", e);
        }
    }
}

补偿操作必须幂等,补偿失败要记录并转人工,不能静默吞掉。

四、可观测:让流程透明

业务流架构师必须回答三个问题:流程卡在哪?为什么失败?谁在处理?

每个状态变更输出结构化日志,记录 traceId、订单号、原状态、新状态、事件、耗时:

代码语言:javascript
复制
@Component
public class FlowAuditListener {
    private final FlowAuditRepository repo;

    @EventListener
    public void onStateChanged(StateChangedEvent event) {
        repo.save(new FlowAudit(
            event.orderId(), event.newState().name(),
            MDC.get("traceId"), Instant.now()));
    }
}

配合 Grafana 看板,实时展示各状态的订单数量、平均停留时长、异常率。当某状态积压超过阈值时自动告警。

五、工程要点

  1. 转移规则数据化:状态机用 Map 或 DSL 定义,便于配置与测试。
  2. 并发控制:乐观锁或分布式锁防止重复推进,幂等键保证重试安全。
  3. 事件解耦:状态变更后发布事件,后续动作异步执行,不阻塞主流程。
  4. 补偿必幂等:Saga 补偿操作必须可重复执行,失败转人工。
  5. 全程可审计:每次状态变更记录上下文,支持追溯与回放。
  6. 人工兜底:异常状态、超时任务、高风险操作进入人工队列,等待恢复。

总结:业务流的核心不是把逻辑写出来,而是把流程建模为可执行、可观测、可恢复的引擎。用状态机约束转移,用编排引擎驱动执行,用 Saga 保障容错,用审计日志实现透明。代码结构清晰,边界明确,业务流才能真正支撑企业级系统的复杂度。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 一、流程建模:状态机是基础
  • 二、编排引擎:事件驱动与持久化
  • 三、异常补偿:Saga 模式
  • 四、可观测:让流程透明
  • 五、工程要点
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档