SRED(State Rotation & Event-Driven)是一个以“状态为中心、事件驱动推进”的工作流/编排引擎。它把复杂业务拆解成显式状态与事件,支持长时间暂停、可持久化恢复的流程执行,适合实现注册、审批、转账等多阶段业务。
- 状态流与转移:声明式定义状态、条件和转移,内置顺序/分支/并行模式
- 事件驱动:以事件推进状态,事件负载会与上下文合并参与决策
- 长时间暂停:可在某些状态自动暂停,支持服务重启后恢复执行
- 持久化:上下文、事件、状态历史可落库(内置 SQLite 适配)
- 注解绑定:
@StateHandler将业务函数绑定至状态 - 类型安全访问:便捷的上下文数据读取 API
- 健康检查与日志:Logback 输出、健康检测
api/Application.kt:Spring Boot 启动入口。controllers/ApiController.kt:REST API(转账与注册),约定返回码:处理中 202,成功 200,明确失败 400。models/:API 请求/响应模型,如RegistrationRequest/Response。services/:API 编排服务,如RegistrationApiService维护引擎、异步执行与恢复。
core/- 基础抽象与内核类型:
Event,StateContext,StateContextImpl,EventFactory, 日志、异常等。 - 负责上下文、事件的标准化与类型安全访问。
- 基础抽象与内核类型:
declarative/- 声明式状态流引擎:
StateFlow,StateMachine及注解绑定。支持顺序/条件/并行/Join 等执行模式。 - 关键点:在顺序模式中,事件 payload 会在调用状态函数前合并到
localState,便于状态函数读取输入。
- 声明式状态流引擎:
event/- 事件总线与分发(内部使用),统计、过滤等。
orchestrator/- 智能编排器,提供“直到完成”的推进、暂停检测、错误处理等高层策略。
persistence/- 持久化适配层,默认 SQLite。负责上下文/事件/状态历史的存取,支持从持久化“恢复实例”。
policy/- 策略加载与版本管理(对高级场景开放)。
health/- 健康检查实现(事件总线/持久化/状态管理等)。
examples/- 示例业务:转账、分支、多工作流、注册等;注册示例包含领域模型、服务与视图。
state/- 低层状态机管理的扩展实现。
SRED.kt- 门面:统一创建
SREDEngine,加载配置、绑定处理器、启动编排器等。
- 门面:统一创建
- 配置加载
- 通过
SRED.fromConfig(configPath, dbPath, handlers)载入 JSON 配置,构建StateFlow → StateMachine,绑定注解函数,创建SREDEngine。 - 如有
dbPath,初始化持久化适配器(如 SQLite)并记录上下文/事件/状态历史。
- 实例启动
engine.start(instanceId, initialData)创建初始上下文(含初始状态),持久化上下文并启动实例。
- 推进执行(两种方式)
- 自动推进:
engine.runUntilComplete(...)循环触发事件处理,直至到达终态或遇到“需暂停”的状态。 - 外部控制:通过
WorkflowExecutor.executeAsync后台推进;当遇到配置了pauseOnEnter=true的状态(如等待验证)自动暂停,等待外部事件唤醒。
- 事件处理
engine.process(instanceId, eventType, eventName, payload)会:- 构建
Event并持久化 - 在
StateMachine.processEvent中,按执行模式选择处理函数 - 顺序模式下:将
event.payload合并到上下文localState后调用状态函数 - 根据
StateResult与转移定义选择下一个状态,更新上下文并持久化
- 构建
- 暂停与恢复
- 当状态定义
pauseOnEnter=true时,进入该状态会写入暂停 metadata,并在WorkflowExecutor中登记为暂停实例。 - 外部通过 API 触发事件(如提交验证码)→ 继续执行 → 若状态发生转移,清除暂停标记并继续推进,直至终态。
- 终态与返回码建议
- 成功终态(名称含
success或配置 FINAL):返回 200 - 明确失败(名称含
failed或 ERROR):返回 400 - 中间处理(非终态/非失败):返回 202(Accepted)
文件:registration.json
- 状态:
registration_initiated(INITIAL)validating→ 校验用户输入sending_email→ 发送验证码waiting_verification(pauseOnEnter=true)→ 暂停等待用户输入verifying_code→ 校验验证码activating→ 激活用户registration_success(FINAL)registration_failed(ERROR)
- 转移条件:
- 典型为
Success/Failure,由StateResult决定。
- 典型为
- 启动期:
Application.kt启动 Spring Boot;RegistrationApiService初始化时创建引擎、注册到执行器、尝试从持久化恢复暂停实例。
- 请求期:
- 发起注册:创建实例并后台推进到
waiting_verification,API 返回 202 与instanceId。 - 提交验证码:将验证码写入上下文并触发
verify事件,后台推进至registration_success,API 在处理中返回 202,成功时 200。
- 发起注册:创建实例并后台推进到
- 关闭期:
- 执行器与引擎关闭:清理任务,释放资源。
涉及文件:
examples/registration/RegistrationStates.kt:状态常量examples/registration/RegistrationDomain.kt:领域模型RegistrationUserexamples/registration/RegistrationService.kt:状态处理器(含@StateHandler)examples/registration/RegistrationFixtures.kt:内存上下文(用户表、验证码表)examples/registration/RegistrationView.kt:示例输出(日志)api/services/RegistrationApiService.kt:注册流程编排(引擎 + 执行器)api/controllers/ApiController.kt:API 暴露registration.json:注册流程配置
状态处理器摘录(关键逻辑):
- 验证输入(
validating):校验用户名、邮箱格式、密码强度与重名;通过则写入validated=true - 发送验证码(
sending_email):生成 6 位验证码写入verificationCodes[email],并把verificationCode写回上下文 - 验证码校验(
verifying_code):比对inputCode与verificationCodes[email],成功写verified=true - 激活账户(
activating):将用户状态置为ACTIVATED,生成userId
执行编排(API 服务的关键点):
- 启动注册:
executeRegistrationengine.start→executor.executeAsync(autoProcess=false),依配置暂停在waiting_verification- 返回 202,携带
instanceId - 开发期日志会打印
验证码已发送到 email: code
- 提交验证码:
submitVerificationCode- 先把验证码写入上下文的
inputCode - 触发
verify事件(eventType=verify, payload={"inputCode": code}) - 若进入中间态(如
verifying_code/activating)返回 202;到达registration_success返回 200;错误返回 400
- 先把验证码写入上下文的
API 一览(/api/v1):
- POST
/registration启动注册,返回 202 和instanceId - POST
/registration/{instanceId}/verify提交验证码,中间态 202,成功 200,错误 400 - GET
/registration/{instanceId}查询状态(随时可用) - GET
/health健康检查
启动服务:
mvn spring-boot:run注册用户:
curl -X POST http://localhost:8080/api/v1/registration \
-H "Content-Type: application/json" \
-d '{"username":"testuser","email":"test@example.com","password":"password123"}'查看验证码:
tail -f logs/sred.log | grep 验证码提交验证码:
curl -X POST http://localhost:8080/api/v1/registration/{instanceId}/verify \
-H "Content-Type: application/json" \
-d '{"verificationCode":"<日志中的验证码>"}'查询状态:
curl http://localhost:8080/api/v1/registration/{instanceId}HTTP 返回码约定:
- 202 Accepted:流程已创建/处理中(未到终态)
- 200 OK:到达成功终态
- 400 Bad Request:明确失败或参数问题
- 500 Internal Server Error:服务器错误
- 状态命名:建议以业务名作前缀,例如
registration_*,终态以_success/_failed结尾便于识别 - 事件命名:
eventType.eventAction或简单eventType,例如verify/process - 数据传递:统一通过
localState传递业务数据;外部事件 payload 会自动合并到localState - 暂停/恢复:把“等待用户输入/外部系统回调”的状态配置为
pauseOnEnter=true - 幂等性:状态函数应尽量保证幂等;必要时检查
context.metadata或数据库 - 可观测性:启用 DEBUG 日志,结合状态历史/事件历史定位问题
- Kotlin、Coroutines、Spring Boot、Jackson、SQLite JDBC、SLF4J/Logback、JUnit 5
常用命令:
mvn clean compile
mvn test
mvn spring-boot:run
mvn clean package- 许可证:MIT
- 欢迎提交 Issue / PR
更多背景与设计动机,可阅读 docs/论 状态轮转与事件驱动结合形架构.md。