文件传输与 EDI

文件没送到,直到周一才有人发现。

文件传输是公司里最老的活儿,通常也是最没人盯的:cron 上的一个 shell 脚本,没有重试,没有告警,没有任何记录。Dagu 保留原有的传输命令,在它周围加上到达等待、验证、重试和历史。

等待文件到达是一个步骤,而不是你自己维护的轮询循环
每次传输都带重试和失败告警
运行在内网中,文件不必绕经云服务
自托管免费,没有按连接数计费的许可
01

没人愿意现代化的集成

订单文件、发票、工资单导出、银行数据和库存对接,至今仍以文件形式按时流转。传输本身早已是解决了的问题,缺的通常是它周围的一切。

  • 脚本知道怎么发文件,但不知道对端宕机时该怎么办
  • 失败往往由下游的人发现,而且常常是几天之后,因为「文件没来」和「今天本来就没数据」看起来一模一样
  • 没人能回答哪个文件、什么时候传的、是否完整,因为没有任何地方记录过
02

等待文件是一个步骤

多数调度器要求你写一个带 sleep 和计数器的轮询循环,然后一直维护它。Dagu 提供等待动作,到达窗口是声明出来的而不是写出来的,而始终没出现的文件会让这次运行失败,而不是把它挂住。

  • wait.file 按你指定的间隔轮询某个路径的出现或消失
  • 加上超时后,一次没送达的投递就变成带告警的失败,而不是一个卡到有人去看才发现的任务
  • 验证作为独立步骤运行,被截断或损坏的文件会在这里停下,而不会进入导入环节
接收:等待、验证、导入、归档
# edi-inbound.yaml
schedule: "0 * * * *"
max_active_runs: 1

s3:
  bucket: corp-edi-archive
  region: ap-northeast-1

steps:
  - id: wait_for_delivery
    action: wait.file
    with:
      path: /var/spool/edi/orders.csv
      poll_interval: 30s
    timeout_sec: 1800

  - id: verify
    run: |
      cd /var/spool/edi
      sha256sum -c orders.csv.sha256
    depends: wait_for_delivery

  - id: import
    run: /opt/core/import-orders.sh /var/spool/edi/orders.csv
    depends: verify
    retry_policy:
      limit: 2
      interval_sec: 300

  - id: archive
    action: s3.upload
    with:
      key: edi/inbound/orders.csv
      source: /var/spool/edi/orders.csv
    depends: import

  - id: mark_done
    action: file.move
    with:
      source: /var/spool/edi/orders.csv
      destination: /var/spool/edi/done/orders.csv
      create_dirs: true
    depends: archive

handler_on:
  failure:
    run: /opt/edi/notify-failure.sh

mail_on:
  failure: true
03

沉默才是真正的故障模式

大声失败的传输是小问题。安静失败的传输会变成一次对账工程。值得补上的正是这层运维能力。

  • retry_policy 覆盖对端短暂不可达的情况,而这正是绝大多数传输失败的原因
  • mail_on.failure 和 handler_on.failure 让一次漏送在同一小时内呼到人
  • max_active_runs: 1 阻止慢速传输与下一次定时执行重叠,避免把同一个文件发两次
04

两端都留在你的边界之内

文件不能离开内网,在金融、医疗和公共部门是常态。跑在你自己主机上的单一二进制,通过 SFTP 抵达对端,本地抵达核心系统,链路中没有第三方服务。

  • sftp.upload 和 sftp.download 以密钥认证传输文件,并可指定跳板机
  • 同一个工作流既能通过 SSH 到达本地系统,也能把归档副本写入对象存储
  • 不经过厂商的云中转,数据驻留和审计问题因此保持简单
发送:抽取、校验和、传输
# edi-outbound.yaml
schedule: "30 18 * * 1-5"
max_active_runs: 1

ssh:
  user: edi
  host: sftp.partner.example.com
  key: ~/.ssh/edi_key

steps:
  - id: extract
    run: /opt/core/export-invoices.sh ./outgoing/invoices.csv
    retry_policy:
      limit: 2
      interval_sec: 120

  - id: checksum
    run: |
      cd ./outgoing
      sha256sum invoices.csv > invoices.csv.sha256
    depends: extract

  - id: send_file
    action: sftp.upload
    with:
      source: ./outgoing/invoices.csv
      destination: /inbound/invoices.csv
    depends: checksum
    retry_policy:
      limit: 3
      interval_sec: 60

  - id: send_checksum
    action: sftp.upload
    with:
      source: ./outgoing/invoices.csv.sha256
      destination: /inbound/invoices.csv.sha256
    depends: send_file

handler_on:
  failure:
    run: /opt/edi/notify-failure.sh

mail_on:
  failure: true
05

留下的是证据,不只是文件

事故之后要回答的通常不是文件里有什么,而是它什么时候到的、是否完整、谁重跑了它。

  • 每次运行都保留分步骤的日志、状态、耗时和重试次数
  • 把归档到对象存储做成工作流的一个步骤,保留策略就从习惯变成了排程
  • 重跑走的是同一条被记录的路径,人工恢复和自动执行一样可见
06

按服务器计价,而不是按连接数

托管文件传输产品通常按连接数、合作伙伴数或传输服务器数授权,所以每接入一个新伙伴账单就会涨一次。

  • 社区版自托管免费,服务器和工作节点数量不限
  • 许可版按 Dagu 服务器计价,并增加 SSO、权限分离和审计日志
  • 接入一个新伙伴就是增加一个工作流文件,许可数量不变
07

什么时候该选托管文件传输产品

Dagu 负责调度和监督传输,它不是完整的 MFT 平台,有些需求确实需要那样的产品。

  • 协议广度:如果需要 AS2、OFTP2 或认证过的 EDI VAN 接入,请用为此而生的产品
  • 面向伙伴的自助门户、按伙伴轮换凭据、不可否认回执,是 MFT 的能力而不是调度器的能力
  • 要求使用认证传输产品的合规体系,不会因为技术上能做到就接受一个通用编排器

FAQ

Practical questions before adopting

Dagu 能取代托管文件传输产品吗?

就定时 SFTP 和基于文件的集成而言,通常可以:它执行传输、等待到达、验证、重试、告警并保留历史。就 AS2、OFTP2、认证 EDI VAN 接入、伙伴自助门户或不可否认回执而言,不能。那些是 MFT 平台的能力,调度器不该假装自己有。

如何按文件到达而不是按时间触发?

用较短的调度间隔运行工作流,并以 wait.file 步骤开头,它会轮询该路径并在文件出现时立即继续。给这个步骤设置超时,这样始终没到的投递会失败并告警,而不是无限等待。如果发送方能主动调用,也可以通过 webhook 从外部启动一次运行。

支持哪些协议?

基于 SSH 的 SFTP 以 sftp.upload 和 sftp.download 内置,S3 兼容的对象存储传输同样内置。其他协议作为普通命令步骤运行,因此 FTPS、rsync 或厂商客户端等现有工具都能继续使用,外面包着调度与监督。

凭据如何管理?

默认使用 SSH 密钥认证,对端位于跳板机之后时也支持跳板配置。密钥在工作流层面声明,并从环境变量、文件、Vault 或云端密钥管理等提供方解析,其值在运行日志中会被遮蔽。

在没有互联网访问的环境能运行吗?

可以。Dagu 是自包含的二进制,不强制要求外部数据库或消息代理,因此能运行在本地和封闭网络中。分布式执行通过你自己网络内的协调器与工作节点之间的 gRPC 完成。

Next step

Start with one workflow.

Install Dagu, move one script that runs on cron today into YAML, and decide from a real run history.