Files
ecm_sync_system/docs/runtime_config_guide.md
2026-04-08 09:28:14 +08:00

14 KiB
Raw Permalink Blame History

运行配置写法说明

这份文档只讲一件事:现在 ecm_sync_system 的配置文件应该怎么写。

重点不是把所有默认值抄一遍,而是说明当前真实生效的写法、哪些字段是内置能力、哪些字段来自业务侧扩展,以及单项目和多项目文件各自长什么样。

1. 先分清两类配置文件

当前有两类 YAML

  1. 单 pipeline 配置
    • 对应 PipelineRunConfig
    • 用来描述一条完整同步链路
    • 顶层通常包含:node_typeslocal_datasourceremote_datasourcepersistloggingstrategies
  2. 多项目编排配置
    • 对应 MultiProjectRunConfig
    • 只负责描述“先跑全局,再按项目并发跑哪些项目”
    • 顶层包含:global_configdefault_project_configmax_concurrencyproject_bootstrap_node_typesprojects

判断规则很简单:

  • 如果文件里有 global_configdefault_project_configprojects,它就是多项目编排配置。
  • 否则按单 pipeline 配置解析。

2. 配置加载约定

当前约定如下:

  • 跟踪在仓库里的模板和示例,只写必要覆盖项,不重复展开默认值。
  • pipeline 启动后会打印一份 Resolved Full Config,它才是最终生效的完整配置。
  • 排障优先看 Resolved Full Config,不要只盯着输入 YAML。

3. 占位符规则

ecm_sync_system 核心库内置只认识一个占位符:

  • ${PROJECT_ROOT}:运行时替换为 ecm_sync_system 仓库根目录绝对路径。

例如:

persist:
  backend: sqlite
  db_path: ${PROJECT_ROOT}/test_results/sync_state_machine/demo.db

需要特别区分的是:

  • ${BACKEND_ROOT}${ECM_SYNC_LOG_DIR} 这类占位符不是核心库通用语义。
  • 它们通常是 backend 集成脚本在读取 profile 时额外替换的调用方语义。
  • 如果你不是通过 backend 的联调脚本运行,而是直接在 ecm_sync_system 内跑 profile,就不要假设这些占位符一定可用。

4. 单 pipeline 配置的当前写法

4.1 最小骨架

node_types:
  - company
  - supplier
  - project

local_datasource:
  type: jsonl
  jsonl_dir: ${PROJECT_ROOT}/filtered_datasource/datasource/filtered

remote_datasource:
  type: api
  api_base_url: http://127.0.0.1:8000/api/third/v2
  api_uid: your_uid
  api_secret: your_secret

persist:
  backend: sqlite
  db_path: ${PROJECT_ROOT}/test_results/sync_state_machine/demo.db

logging:
  file_dir: ${PROJECT_ROOT}/test_results/sync_state_machine
  file_name_pattern: demo_{timestamp}.log

strategies:
  project:
    config:
      auto_bind: true
      auto_bind_fields:
        - name
      local_orphan_action: none
      remote_orphan_action: none
      update_direction: push

4.2 顶层字段含义

  • node_types
    • 本轮参与同步的节点类型列表。
    • 顺序会影响执行顺序,依赖链通常要把上游类型放前面。
  • local_datasource / remote_datasource
    • 定义两侧数据源类型和对应参数。
  • persist
    • 定义持久化后端及目标位置。
  • logging
    • 定义日志初始化、落盘位置和级别。
  • strategies
    • 定义每个 node_type 的同步策略。

5. datasource 字段怎么写

5.1 内置 datasource type

核心库内置注册了两种 datasource type

  1. jsonl
  2. api

jsonl 写法

local_datasource:
  type: jsonl
  jsonl_dir: ${PROJECT_ROOT}/filtered_datasource/datasource/filtered
  read_only: false
  handler_configs:
    project:
      data_id_filter:
        - project-id-1

字段说明:

  • jsonl_dirJSONL 数据目录。
  • read_only:是否只读。
  • handler_configs:按 node_type 下发给 handler 的扩展参数。

api 写法

remote_datasource:
  type: api
  api_base_url: http://127.0.0.1:8000/api/third/v2
  api_uid: your_uid
  api_secret: your_secret
  api_debug: true
  poll_max_retries: 10
  poll_interval: 0.5
  api_rate_limit_max_requests: 30
  api_rate_limit_window_seconds: 10.0
  handler_configs:
    project:
      data_id_filter:
        - remote-project-id-1

字段说明:

  • api_debug:开启后输出更详细的请求日志。
  • poll_max_retries / poll_interval:异步任务轮询控制。
  • api_rate_limit_max_requests / api_rate_limit_window_seconds:全局限流窗口。
  • handler_configs:同样按 node_type 下发业务参数。

5.2 业务侧注册的 datasource type

核心库允许业务系统在启动阶段注册自己的 datasource type。

因此,配置里不只可以写 jsonlapi,还可以写业务侧注册出来的类型,例如 backend 里的 depm_db

当前 backend 的 depm_db 真实写法是:

local_datasource:
  type: depm_db
  tenant_id: "019976df-0628-7c46-a896-81d3f290a7df"
  app:
    config_file: ${BACKEND_ROOT}/config.yaml
    overrides:
      database:
        url: mysql+aiomysql://root:123456@127.0.0.1/depm_prod_local_auto_test?charset=utf8mb4
  handler_configs:
    project:
      data_id_filter:
        - 019a62a5-2323-7be2-99c8-82534f8befa4

这个例子说明两点:

  1. datasource 的可写字段由对应注册模型决定,不是所有 type 都共用同一套字段。
  2. 如果 type 没有先被注册,配置校验会直接报错,不会做降级处理。

depm_db 这类业务扩展字段需要以业务侧实现为准。对 backend 当前实现来说:

  • tenant_idDEPM 本地 datasource 的租户过滤 ID。
  • app.config_file:backend 配置文件路径,默认可落回 backend/config.yaml
  • app.overrides:直接传给 backend Settings() 的覆盖项。

6. strategy 写法

6.1 当前推荐写法

strategies 现在推荐写成“按 node_type 为键”的映射,而不是手工写一长串列表。

strategies:
  supplier:
    skip_post_check: true
    config:
      auto_bind: true
      auto_bind_fields:
        - credit_code
      depend_fields: {}
      local_orphan_action: none
      remote_orphan_action: create_local
      update_direction: none
  project:
    domain_option:
      pull_group_plan_production_date: true
    config:
      auto_bind: false
      auto_bind_fields: []
      pre_bind_data_id:
        - local_data_id: local-project-id
          remote_data_id: remote-project-id
      depend_fields:
        company_id: company
      local_orphan_action: none
      remote_orphan_action: none
      update_direction: push

6.2 常用字段

  • auto_bind
    • 是否开启自动绑定。
  • auto_bind_fields
    • 自动绑定使用的业务键字段。
  • pre_bind_data_id
    • 显式 local/remote data_id 绑定对。
  • depend_fields
    • 依赖字段到依赖 node_type 的映射。
  • local_orphan_action / remote_orphan_action
    • 孤儿节点创建策略。
  • update_direction
    • push / pull / none
  • post_check_ignore_fields
    • 只影响最终一致性检查,不影响 create/update 差异检测。
  • compare_ignore_fields
    • schema diff / validate 时忽略的顶层字段。
  • skip_sync
    • 只跳过 create/update,不跳过 load/bind。
  • skip_post_check
    • 跳过该类型的 post-check reload 与一致性校验。
  • domain_option
    • 领域策略自己的扩展参数,由对应 domain 自己解释。

6.3 preset 仍然可用

如果只是想套一组预设策略,可以这样写:

strategies:
  project:
    preset: pull_only

当前内置预设包括:

  • first_sync
  • daily_sync
  • repair_sync
  • pull_only
  • push_only

6.4 已废弃的旧字段不要再写

以下 legacy key 已明确拒绝:

  • force_sync
  • load_mode

如果你在 strategy 里写这两个字段,配置会直接报错。

当前替代方式是:

  • 是否跳过同步,用 skip_sync
  • handler 特有加载参数,写到 datasource.handler_configs.<node_type>

7. persist 的当前写法

7.1 校验规则

当前 persist 配置遵循下面的规则:

  1. db_pathurl 至少要有一个。
  2. backend != sqlite 时,必须显式提供 url
  3. wipe_on_start=true 只会尝试删除可映射到文件路径的持久化文件;对 MySQL 这类远程数据库不会帮你删库。

7.2 SQLite 文件持久化

persist:
  backend: sqlite
  db_path: ${PROJECT_ROOT}/test_results/sync_state_machine/simple_pipeline_sm.db
  enable: true
  wipe_on_start: false

7.3 SQLAlchemy 持久化到 SQLite URL

persist:
  backend: sqlalchemy
  url: sqlite+aiosqlite:////abs/path/to/pipeline.db
  enable: true
  wipe_on_start: false

7.4 SQLAlchemy 持久化到 MySQL

persist:
  backend: sqlalchemy
  url: mysql+aiomysql://root:123456@127.0.0.1/ecm_sync_system?charset=utf8mb4
  enable: true
  wipe_on_start: false

当前语义:

  • sqlalchemy backend 会自动创建它自己的 nodesbindings 表及索引。
  • 它不会替你创建 MySQL 数据库本身,所以 ecm_sync_system 这个库需要提前存在。
  • 现有表结构已经兼容 MySQL,不需要再额外给主键字段手工指定前缀长度。

7.5 backend_options 什么时候用

backend_options 仍然保留,但现在优先使用显式字段:

  • db_path
  • url
  • enable
  • wipe_on_start

除非某个自定义 backend 明确要求,否则不要把主连接信息再塞进 backend_options

8. logging 的当前写法

logging:
  initialize: true
  file_dir: ${PROJECT_ROOT}/test_results/sync_state_machine
  file_name_pattern: simple_pipeline_sm_{timestamp}.log
  level: 20
  suppress_node_logs: true

字段说明:

  • initialize
    • 是否初始化应用日志。
  • file_path
    • 直接指定日志文件绝对路径。
  • file_dir
    • 只指定目录时,实际文件名由 file_name_pattern 生成。
  • file_name_pattern
    • 支持 {timestamp} 占位。
  • level
    • 默认 20,即 INFO
  • suppress_node_logs
    • 是否压缩逐节点日志噪音。

9. 多项目编排文件怎么写

9.1 结构

多项目文件不是把所有字段都堆在一起,而是引用两份单 pipeline 配置:

global_config: run_profiles/jsonl_to_jsonl.multi_project.global.yaml
default_project_config: run_profiles/jsonl_to_jsonl.multi_project.project.yaml

project_bootstrap_node_types:
  - company
  - supplier

max_concurrency: 8

projects:
  - local_project_id: local-project-1
    remote_project_id: remote-project-1
  - local_project_id: local-project-2
    remote_project_id: remote-project-2

字段说明:

  • global_config
    • 全局公共节点要跑的单 pipeline 配置。
  • default_project_config
    • 每个项目默认使用的单 pipeline 配置。
  • project_bootstrap_node_types
    • 需要从 global scope 继承到项目 scope 的公共节点类型,例如 companysupplier
  • max_concurrency
    • 项目并发数上限,默认 20
  • projects
    • 项目映射清单。

9.2 项目项支持单独切配置

如果某个项目需要特殊策略,可以在项目项里覆盖 config_path

projects:
  - local_project_id: local-project-1
    remote_project_id: remote-project-1
  - local_project_id: local-project-2
    remote_project_id: remote-project-2
    config_path: run_profiles/special_project.pipeline.yaml

此时该项目不会再用 default_project_config,而是改用自己的单 pipeline 配置文件。

9.3 当前多项目 profile 的实际风格

以当前 backend 两项目推送链路为例,常见组合是:

  • local_datasource.type: depm_db
  • remote_datasource.type: api
  • persist.backend: sqlalchemy
  • persist.url: mysql+aiomysql://...
  • strategies.project.config.pre_bind_data_id 明确写每个项目的 local/remote 映射

这类 profile 本质上仍然是“多项目编排文件 + 两份单 pipeline 文件”的组合,不要把它理解成第三种配置格式。

10. 当前推荐的写法习惯

10.1 只写必要覆盖项

推荐:

  • 只写与你当前环境、项目过滤、持久化目标、策略差异直接相关的字段。

不推荐:

  • 把默认值全部展开复制一遍。

原因很直接:

  • 默认值一旦调整,你的大段本地 YAML 会悄悄过时。
  • 排障时也更难看出你到底改了什么。

10.2 handler 特有参数放 datasource 里

比如:

remote_datasource:
  type: api
  handler_configs:
    contract_settlement_detail:
      load_method: aggregate

这类参数应该写在 datasource.handler_configs.<node_type>,不要错写到 strategy 里。

10.3 项目过滤显式下沉到 handler

例如:

handler_configs:
  project:
    data_id_filter:
      - project-id-1
      - project-id-2

不要在 pipeline 外层再做一层临时过滤逻辑。项目范围应尽量体现在配置里,并由对应 handler 解释。

10.4 看到报错先修配置,不要做降级

当前系统对配置保持 fail-fast:

  • datasource type 未注册会报错
  • legacy strategy key 会报错
  • persist 缺失目标会报错
  • profile 结构不符合 schema 会报错

这属于预期行为。优先修正配置,而不是在文档或调用侧加 fallback。

11. 参考文件

如果你想直接对照真实样例,优先看这些文件:

  • run_profiles/jsonl_to_api.yaml
  • run_profiles/jsonl_to_jsonl.multi_project.yaml
  • backend 中的 local_tests/sync_system_tests/depm_to_ecm_bootstrap_pull_then_project_push.two_projects.sqlalchemy.pipeline.yaml

如果你想看配置模型定义,直接看:

  • sync_state_machine/config/pipeline_config.py
  • sync_state_machine/config/datasource_config.py
  • sync_state_machine/config/persist_config.py
  • sync_state_machine/config/multi_project_config.py
  • sync_state_machine/config/strategy_config.py

排障时优先顺序:

  1. 看输入 YAML。
  2. 看启动日志里的 Resolved Full Config
  3. 看对应 datasource type 是否真的已经注册。
  4. 再看运行日志和状态机结果。