
简介面向Dify平台用户的开源辅助工具针对Dify官方缺乏定时任务能力的痛点借助GitHub Actions实现工作流的按时触发与执行并在完成后通过邮件等方式发送通知从而提升自动化管理水平。压缩包共18个文件大小415KB主要包含中英文日文说明文档、JavaScript脚本工作流调用、通知、环境变量处理等模块、GitHub Actions的YAML配置以及界面演示图结构清晰便于快速定位所需内容。当前已有495人学习下载。使用者可参考其中的示例脚本和配置模板快速搭建定时调度方案避免从零开始同时还能学习如何将Dify API与外部自动化平台衔接理解脚本模块划分与工程组织方式适合有一定脚本基础、希望扩展Dify能力的开发者。1. Dify工作流定时助手把“没人盯”的活儿交给调度器工作流如果只能靠人点一下才跑价值就少了一半。Dify工作流里“定时助手”这个节点本质是一个内置Cron触发器时间条件一旦满足它就帮用户把工作流真正启动一次并把调度上下文作为变量交给下游节点。它最常用的场景是日报推送、知识库定期刷新、外部系统数据拉取以及那些不需要实时响应但必须按点执行的任务。对刚做完Dify本地部署的团队来说这个节点通常是第一个被试验的自动化节点对已经用轻量级工作流取代手工操作的人来说定时助手则是把“无人值守”落地的关键。下面从触发机制开始把参数和调试方法一起讲透。2. 定时助手的触发机制与Cron表达式选型2.1 Dify调度器怎么把“时间”变成“工作流实例”在Dify工作流的设计里定时助手并不单独执行业务逻辑它只负责“叫醒”整个流程。常见做法是平台内部维护一个调度器社区版Dify由独立的worker进程承载它按Cron频率扫描即将到期的任务。只要匹配到当前分钟就为对应工作流创建一条带调度上下文的任务记录再交给执行引擎去跑。这个机制决定了两个特性定时助手不是实时抢占最小粒度通常到分钟级如果worker集群有多副本需要确保同一个任务同一时刻只有一个实例被发出避免重复执行。2.2 定时表达式从最小粒度到复杂周期怎么选Dify的定时助手采用标准五段Cron顺序是分 时 日 月 周。最小粒度是分钟不支持秒级任务。下面几组表达式是我在项目里最常用的需求Cron表达式含义每天08:3030 8 * * *每天上午8点30分触发每个工作日9点0 9 * * 1-5周一到周五上午9点触发每月1号0点10分10 0 1 * *每月1日0点10分触发每30分钟一次*/30 * * * *每隔30分钟触发一次每小时整点0 * * * *每小时整点触发注意五段Cron里星期字段是0-70和7都表示周日这与其他系统略有差异。Dify处理无效日期比如31 2 * *时会按“尽可能跳过”处理但为了让定时助手行为可预期我建议把这类防御性校验放在工作流入参层不要依赖调度器本身的容错。另外有些人会把“每天早上9点”写成0 9 * * 1-5只覆盖工作日但业务方口中的“每天早上”往往是包含周末的。我一般会先和需求方确认自然语言里的“每天”到底对应一周七天还是工作日再映射成Cron否则上线三周后一定会有人来问“为什么周六没有跑”。2.3 调度上下文定时助手往下游传了哪些变量定时触发进入工作流后它不只是把任务拉起还会带一些上下文变量。在设计工作流时我一般会在第一个节点直接引用这些变量不额外查库sys.scheduled_time本轮计划执行时间格式通常是ISO 8601带时区偏移sys.trigger_type写死为scheduled用来区分是手动调试还是定时触发自定义输入如果在定时助手配置里追加了参数同样会以变量形式暴露给下游节点这段代码演示在代码节点里读取这些变量并生成可读时间import datetime scheduled_time arg_vars.get(sys.scheduled_time) if scheduled_time: dt datetime.datetime.fromisoformat(scheduled_time) readable dt.strftime(%Y-%m-%d %H:%M:%S) print(本轮触发时间:, readable) trigger_type arg_vars.get(sys.trigger_type) print(触发来源:, trigger_type)这段代码的逻辑是在代码节点中定义arg_vars作为Dify传入的变量字典分别取出计划时间和触发来源。参数说明sys.scheduled_time是Dify平台在任务命中时写入的固定字段不是自己手工加的参数fromisoformat能直接解析带时区偏移的字符串但如果部署版本返回的是Unix时间戳就要改用datetime.fromtimestamp()。3. 在Dify本地部署环境里搭一个定时工作流3.1 最小可用案例定时把一段消息发到Webhook先给一个不需要接大模型就能跑通的最小场景每天10点把一句话POST到指定Webhook。这个案例用来验证定时助手本身避免把生成模型和HTTP请求问题混在一起。Dify工作流编辑器里的节点连线大体是定时助手-代码-HTTP请求。代码节点负责组装请求体HTTP请求节点负责发送。实现时代码节点里可以这样写import json payload { title: 定时任务触发通知, content: 这是由Dify定时助手触发的消息, trigger_time: arg_vars.get(sys.scheduled_time, ) } return {request_body: json.dumps(payload, ensure_asciiFalse)}逻辑说明代码节点接收上游定时助手的sys.scheduled_time把业务字段和触发时间一起打成JSON字符串返回给request_body变量HTTP请求节点再把request_body放到POST body里。需要特别留意的参数是上游节点的变量名Dify里下游引用上游输出时要用“节点ID.输出”的形式如果你把代码节点的ID改成了format_msg引用时就写format_msg.request_body。3.2 手动测试与定时测试分开跑Dify工作流的运行入口分为“运行”和“定时触发”两种。手动点击界面上的“运行”按钮时即使配置了定时助手也会按手动方式生成一次执行这时sys.trigger_type会返回manual。因此我做调试的习惯是先手动运行一次看代码节点和HTTP节点有没有报错再去“定时管理”里把触发频率改成*/1 * * * *等一分钟确认能自动跑起来跑通后再改回正式周期如果在Dify社区版使用Docker Compose部署我一般会这样查看worker日志docker compose logs -f worker | grep scheduled task这条命令会把worker容器输出里带“scheduled task”的日志实时显示出来。看到这句日志说明调度器已经把任务发给了执行引擎如果一直没有这句说明Cron表达式没有命中或者worker没有拿到定时任务的配置更新。3.3 定时任务配置表从哪里进、字段怎么填在Dify的“编排”区域添加定时助手节点实际字段只有几个配置项填写内容说明Cron表达式0 10 * * *标准五段格式精确到分钟时区Asia/Shanghai不填默认使用服务器时区常见坑是否启用开/关关闭后保留配置但不再触发自定义参数scenedaily_reportlimit20可传给工作流需要在下游定义变量接收参数说明时区这一项影响最大。如果服务器时区是UTC而没写Asia/Shanghai0 10 * * *指的是UTC10点也就是北京时间18点表现就是“定时时间莫名其妙差8小时”。自定义参数适合放渠道标识或拉取条数下游代码节点可以用arg_vars.get(scene)读取。4. 定时助手必调的3个参数与运行超时排查4.1 调整Cron的幂等保护重复执行的拦截定时任务翻车通常不是配置错而是业务逻辑不具备幂等性。比如任务在10:00执行了但worker网络抖动导致任务重试同一分钟又被跑了一次。社区版Dify在调度层做了一定去重但依赖任务唯一ID如果你用Dify工作流去调外部系统外部系统不一定有这种天然去重机制。所以在定时助手的下游我通常在第一代码节点按业务日期生成一个去重键import hashlib dedup_key hashlib.md5( (str(arg_vars.get(sys.scheduled_time, )) _daily_report).encode() ).hexdigest() return {dedup_key: dedup_key}这段代码取调度时间和业务场景名拼接成MD5用来判断这次任务是否已经处理过。它解决的是“同一分钟重复触发”的问题如果外部系统需要更严格的互斥可以把dedup_key写入Redis并设置过期时间过期前重复请求直接返回。4.2 “任务没跑”先从这三个方向查遇到定时助手到点不干活我的排查顺序固定是先看时间再看日志最后看并发。时间问题Dify后台显示的时间是不是本地时间如果页面写“下次执行10:00”但实际等于UTC的10点说明时区没同步。可以在worker容器里执行date -R确认当前时区。日志问题用上一章的docker compose logs -f worker看有没有scheduled task日志如果worker只打印了task received但没有task succeeded问题在业务节点而不是定时触发。并发问题如果上一个任务执行了30分钟还没结束下一个时间点又到了worker队列会堆积。社区版默认并发参数有上限表现为任务晚点执行而不是丢失。可以通过docker compose ps看worker状态确认容器没有因为占用过高而被OOM杀掉。具体到date -R这条命令它输出的是RFC 2822格式含时区缩写。如果你看到的是0000而不是0800说明容器时区没有挂载本地/etc/localtime这时要在docker-compose的worker环境变量里加TZAsia/Shanghai再重启。4.3 定时助手运行结果怎么验证除了看日志我会在工作流结尾加一个“结果确认”分支HTTP请求返回200就结束返回非200则把错误信息写回失败原因变量再触发一个只有失败才走的通知节点。这样定时任务执行完失败原因在Dify“运行历史”里一眼能看到。curl -s -o /dev/null -w %{http_code} http://localhost:8000/healthz上面这条命令常用来快速确认服务还活着。如果定时任务是调用内部接口先用这条命令确认接口本身没问题再判断定时助手要不要背锅。还有一种更容易被忽略的情况任务确实跑了但在Dify工作流页面里看不到日志。这是因为定时执行走的是后台worker日志入口在“运行历史”里而不是“实时运行”面板。手动点击“运行”是前端直连执行引擎这两者的日志路径不一样。5. 用定时助手串起知识库和数据同步的实操技巧在Dify工作流里定时助手最适合和知识库“流水线”配合。常见做法是每天定时从RSS抓文章写入知识库再生成一份摘要推送到飞书群机器人。这个过程有三个技巧。第一每个任务都带sys.scheduled_time用当天日期做分片字段方便增量写入。比如同步任务的下游代码节点先截取日期再去查外部接口的updated_at只拉取晚于这个时间点的数据避免全量扫描。第二把“连续失败3次”作为暂停条件。定时助手本身没有内置熔断我会在工作流外加一个状态记录表每次失败在Redis里累加计数计数达到3就把Cron表达式改成一个永远不会触发的时间比如0 0 30 2 *让任务不再空转。第三回调地址不建议每次请求都新建一个Webhook而是直接在Dify里建一个固定入站节点靠scene参数区分业务。定时助手的自定义参数里写scenerss_sync入站节点拿到之后就走到不同的业务分支这样多个定时任务可以共用同一个入口逻辑收敛。验证定时助手是否稳定运行可以自己写一段心跳脚本每5分钟向工作流入站地址发一条带heartbeat标记的POST请求再在工作流里对heartbeat分支做记录。连续N次没收到心跳就说明调度链路出了问题这时候再到worker日志里查missed task字段。设计周期时平均任务时长建议控制在周期的一半以内。如果周期为1小时任务最好跑30分钟以内如果经常超时就把同步拆分到多个定时工作流而不是在一个工作流里串更多节点。定时助手真正要盯的不是“能不能触发”而是大规模落地时不重复、不追尾、不积压。本文还有配套的精品资源点击获取