Appearance
业务数据入库(persist 组件)
1.6.2 起随主包发布(
jeeflow.persist模块)
persist.py:引擎无关的动态表写入组件 + 工作流入库适配拦截器。 规范契约见文档站《09 · 业务数据通用入库》;本页是 Python 语言视角。
引入
python
from jeeflow.persist import JdbcDynamicTableWriter, PersistPostInterceptor动态表写入(引擎无关)
python
conn = sqlite3.connect("biz.db") # 或 pymysql / psycopg2 连接
writer = JdbcDynamicTableWriter(conn) # sqlite3 连接自动识别方言,其余走 information_schema
# ① 列过滤
kept = writer.filter_columns("biz_leave", ["title", "ghost_col"])
# ② 幂等检查
ok = writer.exists("biz_leave", "process_instance_id", inst_id)
# ③ 系统字段填充 + 参数化插入
data = {"title": "年假申请"}
writer.fill_system_fields(data, True)
writer.insert("biz_leave", data)安全:sys_ 前缀表拒绝写入;非法字符表名拒绝;值走参数化占位符。 列匹配(1.6.4):默认宽松——驼峰表单字段 ↔ 下划线表列(companyName → company_name),严格模式可配置。 主键生成(1.6.5):非自增主键表(雪花/应用生成)注册生成器后自动补主键;未配置时清晰报错。
流程入库拦截器(流程结束同意自动落表)
python
writer = JdbcDynamicTableWriter(conn)
ic = PersistPostInterceptor(writer=writer, loader=repo.find_define_by_id) # loader 透传 findDefineById
eng.set_extensions(EngineExtensions(interceptors=[ic]))- 拦截器挂在引擎全局 Extensions;内部按「结束节点 + 实例 DONE + submitType=AGREE」过滤, 仅对流程定义顶层声明了
relTableName(缺省回落流程 name)的流程生效 - 语义:实例
f_字段(去前缀)+ 流程上下文(process_instance_id/apply_user_id/apply_dept_id)- 系统字段写入业务表;
process_instance_id幂等(先查后插)+ 同链内存标记(1.6.3,共享 instance.variables,不落库);用户列默认取 operator(1.6.3);表不存在显性报错(ValueError, 配置错误快速失败);不同意/退回不入库
- 系统字段写入业务表;
- 引擎对齐(1.6.2):任务完成后结束节点统一走
_execute_node,拦截器在流程结束时完整触发
流程定义配置字段语义(顶层,与 name/nodes 同层):
| 字段 | 取值 | 语义 |
|---|---|---|
relTableName | 表名 | 业务表名——数据写入哪张表;缺省回落流程 name;表不存在 = 配置错误显性报错 |
persistMode | ARCHIVE / SYNC(缺省 ARCHIVE) | 持久化模式——ARCHIVE:流程结束且同意落库一次;SYNC:发起即入库 → 节点推进 → 结束定稿,全程留痕。非 SYNC 值回落 ARCHIVE |
同步演进模式(SYNC,1.8.0)
流程定义顶层加 "persistMode": "SYNC"(缺省 ARCHIVE——保持"结束同意归档"不变), 改为全程留痕:提交申请即入库(start 节点 INSERT 全量)→ 任务节点推进 UPDATE → 结束节点定稿最终状态(FINISHED=20 / REJECT=45),不管成功失败都入库。
- 状态字段:值 = 实例状态码,列名优先
{节点ID}_{状态码}(如task1_10), 无该列回落{节点ID}(如task1);任务节点统一写 DOING(10)(任务推进状态), 结束节点写实例最终状态 - 字段权限(任务节点级):节点
properties.field声明——键格式双兼容:PERMISSION_f_{表单字段全名}(前端 vben5-wf 设计器约定,优先)与PERMISSION_{去前缀名}(1.8.0 首版格式,兼容),两种都匹配(1.8.1 起);值1只读 /2可编辑 /3隐藏 (缺省可编辑);权限管控「办理时可提交的字段」——只读/隐藏字段办理提交的值在引擎入口 过滤不入变量(1.8.2),下游无权限节点也无法写入(变量里没有被拒值),上游只读不可绕过; 非任务节点不覆盖业务字段(只定稿状态) tf_冗余:任务节点提交的tf_前缀变量(如tf_opinion审批意见)去前缀冗余到 业务表对应列(列过滤由 writer 做,无列则丢弃)- 幂等:同链标记改节点级(
__persist_executed_{instanceId}_{节点ID})——任务推进与 结束定稿是不同节点都要生效;process_instance_id先查后插/更兜底 - writer.update:参数化 UPDATE(列过滤组装 SET、条件列排除防注入),
update(tableName, data, "process_instance_id", instanceId)
示例:{"persistMode": "SYNC", "relTableName": "biz_leave", ...},业务表建 apply / task1 / finish 状态列(INT)+ opinion 列(tf_ 冗余,可选)。
测试
bash
python -m pytest tests/test_persist.py -q # 9 用例:writer 4 + 拦截器集成 5(SQLite 内存库全链路)