ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

Conductor 工作流定时调度实战:Cron 调度器、时区语义与生产配置指南

Conductor 工作流定时调度实战:Cron 调度器、时区语义与生产配置指南 Conductor 工作流定时调度实战Cron 调度器、时区语义与生产配置指南【免费下载链接】conductorConductor is an event driven agentic workflow engine providing durable and highly resilient execution engine for applications and AI Agents项目地址: https://gitcode.com/GitHub_Trending/co/conductor本文围绕 Conductor 事件驱动的 Agentic 工作流引擎中的调度器Scheduler模块系统讲解如何为工作流创建 Cron 调度、理解时区与夏令时行为、启用追赶Catchup与时间窗口Bounds、使用调度器注入的输入字段并通过 CLI 与完整 REST 接口完成调度的创建、预览、暂停、恢复与历史检索。读完本文你将掌握在 Conductor 中以“时钟驱动”方式按时、按区、可追溯地触发工作流的完整实操方案。何时使用调度器时钟驱动 vs 事件驱动Conductor 的调度器会在每一个匹配的 Cron 槽位cron slot上创建一次新的工作流执行。其适用场景是由时钟来决定“何时运行”与之相对当由**消息来决定“何时运行”**时应当使用事件编排Event Orchestration。两者边界清晰调度器固定时刻、周期性触发例如每日报表、定时清理、定期聚合事件编排由事件总线上的消息触发例如订单创建、支付回调、外部 webhook。调度器模块的 REST 控制器挂载在/api/scheduler下并且仅当conductor.scheduler.enabledtrue默认值时才会装配见 SchedulerResource.java 中的Conditional(SchedulerConditions.class)与RequestMapping(/api/scheduler)。前置条件在开始创建调度之前需要确认以下条件全部满足目标工作流定义WorkflowDef已注册到 Conductor 元数据服务服务端已启用调度器且其持久化模块已配置如conductor-scheduler-postgres-persistence、conductor-scheduler-mysql-persistence、conductor-scheduler-redis-persistence、conductor-scheduler-cassandra-persistence等见 scheduler 模块下的各 persistence 子模块目标工作流所需的 Worker 正在运行已配置 Conductor CLI 用于简单的 CRUD 操作或可通过 REST 使用完整的调度器模型。创建第一个简单调度仓库中提供了一个可直接运行的规范示例 every-minute-schedule.json它代表每分钟在 UTC 时区触发一次{ name: every-minute-demo-schedule, cronExpression: 0 * * * * *, zoneId: UTC, startWorkflowRequest: { name: daily_report_workflow, version: 1, input: {} }, runCatchupScheduleInstances: false, paused: false }使用 Conductor CLI 创建并读取该调度conductor schedule create scheduler/examples/every-minute-schedule.json conductor schedule get every-minute-demo-schedule成功判据有两点调度已保存且nextRunTime非空下一个 Cron 槽位之后出现一次对应的工作流执行。CLI 与 REST 的能力边界CLI 是“简单 CRUD”入口并非所有调度器字段和操作都能在 CLI 的各个发行版本中一致暴露。对于多表达式 Cron、时间窗口bounds、追赶行为catchup、执行时间预览、执行历史检索等高级能力请使用 REST 接口。使用完整的 REST 接口调度器的核心 CRUD 端点均返回200 OK成功时。创建或更新一个调度curl -sS -X POST http://localhost:8080/api/scheduler/schedules \ -H Content-Type: application/json \ --data-binary scheduler/examples/every-minute-schedule.json同一个POST /api/scheduler/schedules按调度名执行“创建或更新”create-or-update响应体为存储后的调度对象其中包含服务端计算的状态字段如nextRunTime。完整的请求体字段、查询参数与状态码请参考 Scheduler API 文档。调度模型字段一览调度对象对应源码中的WorkflowSchedule模型见 WorkflowSchedule.java字段类型是否必填运行时默认值或行为namestring是唯一键用于创建或更新cronExpressionstring两种 Cron 形式必填其一传统的单表达式zoneIdstring否UTCcronSchedulesarray两种 Cron 形式必填其一非空数组时优先于cronExpression/zoneId每个条目的zoneId默认UTCstartWorkflowRequestobject是标准的工作流启动请求runCatchupScheduleInstancesboolean否falsepausedboolean否falsepausedReasonstring否由暂停操作设置scheduleStartTimelong否时间窗口下界epoch 毫秒scheduleEndTimelong否时间窗口上界epoch 毫秒descriptionstring否用户描述createTime、updatedTime、createdBy、updatedBy、nextRunTime服务端字段否由服务端填充从源码可以确认两个关键行为WorkflowSchedule.getEffectiveCronSchedules()在cronSchedules非空时优先返回该列表否则回退到单元素列表cronExpression zoneIdzoneId为空时兜底UTCCronSchedule条目本身也只含cronExpression与默认为UTC的zoneId两个字段见 CronSchedule.java。Cron 与时区行为Spring 六字段 Cron 表达式Conductor 调度器使用Spring 六字段 Cron 表达式秒、分、时、日月、月、星期day of week。同时 Spring 解析器也接受daily之类的宏┌─────────────── second (0-59) │ ┌───────────── minute (0-59) │ │ ┌─────────── hour (0-23) │ │ │ ┌───────── day of month (1-31) │ │ │ │ ┌─────── month (1-12 or JAN-DEC) │ │ │ │ │ ┌───── day of week (0-7 or MON-SUN) │ │ │ │ │ │ * * * * * *常用表达式示例表达式含义0 * * * * *每分钟0 0 9 * * MON-FRI工作日 09:000 0 0 1 * *每月第一天 00:000 0/30 9-17 * * MON-FRI工作时间内每 30 分钟单表达式与多表达式多时区单表达式形式使用cronExpression加zoneId默认UTC多表达式形式使用cronSchedules数组当该数组非空时它优先于cronExpression/zoneId两个传统字段且每个条目可独立指定zoneId默认UTC。一个典型的多时区场景——同一工作流分别在美国东部与伦敦的当地 9 点触发{ name: regional-report, cronSchedules: [ {cronExpression: 0 0 9 * * MON-FRI, zoneId: America/New_York}, {cronExpression: 0 0 9 * * MON-FRI, zoneId: Europe/London} ], startWorkflowRequest: { name: daily_report_workflow, version: 1 } }夏令时DST下的求值语义Cron 求值遵循所选 IANA 时区包括夏令时转换春季“向前拨”spring-forward时不存在本地时间该本地时刻会被 Cron 引擎跳过重复出现的本地时间秋季回拨遵循引擎的“下一时刻”计算规则。因此对业务敏感的调度务必在 DST 边界前后进行测试验证。预览执行时间Preview的时区注意点预览端点不接受时区参数它在conductor.scheduler.schedulerTimeZone默认UTC下求值而不是调度自身的zoneId并且无论limit传多大最多只返回 5 个时间。这与调度实际执行时所遵循的时区可能存在差异使用时需留意。curl http://localhost:8080/api/scheduler/nextFewSchedules?cronExpression0*****limit5该端点对应源码中的getNextFewSchedules见 SchedulerResource.javalimit的默认值即为 5。追赶Catchup与时间窗口Bound停机后的追赶执行runCatchupScheduleInstances: true会在停机恢复后逐个推进错过的 Cron 槽位为每一个错过的槽位各触发一次执行。仓库中的 catchup-schedule.json 即为此模式的示例{ name: catchup-demo-schedule, cronExpression: 0 * * * * *, zoneId: UTC, runCatchupScheduleInstances: true, paused: false, startWorkflowRequest: { name: catchup_demo_workflow, version: 1, input: {} } }需要注意追赶可能造成执行突刺burst因此目标工作流及其下游依赖必须满足幂等且具备容量意识。当使用默认值false时调度器从当前时间继续推进而不会重放每一个错过的槽位。观察追赶行为的方法停止 Conductor 数分钟重启后即可看到针对错过的槽位按顺序触发的一系列执行。时间窗口scheduleStartTime / scheduleEndTime使用scheduleStartTime与scheduleEndTime均为 epoch 毫秒、含边界把调度限制在一个窗口内。超出窗口的调度会停止产生新的执行但不会被自动删除。模板示例见 bounded-schedule-template.json其中__START_MS__/__END_MS__为占位符可用sed替换后提交NOW$(($(date %s) * 1000)) END$((NOW 300000)) # 5-minute window sed s/__START_MS__/$NOW/; s/__END_MS__/$END/ scheduler/examples/bounded-schedule-template.json | \ curl -sS -X POST http://localhost:8080/api/scheduler/schedules \ -H Content-Type: application/json -d -调度器注入的输入字段每次调度触发的执行调度器会先复制startWorkflowRequest.input再向工作流输入中追加以下 5 个字段。其实现证据位于 SchedulerService.java输入字段含义_startedByScheduler调度名称_scheduledTime预期的 Cron 槽位时间epoch 毫秒_executedTime实际派发时间epoch 毫秒_executionId唯一的调度执行记录 ID_schedulerCron产生本次执行的 Cron 表达式与时区当下游系统需要“每次运行唯一标识”时可在工作流中使用${workflow.input._executionId}。仓库示例 input-param-schedule.json 展示了静态入参reportOwner、alertThreshold与注入字段并存{ name: input-param-demo-schedule, cronExpression: 0 * * * * *, zoneId: UTC, runCatchupScheduleInstances: false, startWorkflowRequest: { name: input_param_demo_workflow, version: 1, input: { reportOwner: platform-team, alertThreshold: 100 } } }一个真实运行中可见的时序差异来自 scheduler/examples/README.md 的实测记录scheduledAt: 2026-02-19T23:22:00.000Z ← 精确的 cron 槽位 triggeredAt: 2026-02-19T23:22:00.837Z ← 实际派发约 837ms 轮询开销correlationId 的“字面量”语义startWorkflowRequest.correlationId会被原样复制调度器不会在其中插值${scheduledTime}等模板。如果需要每个工作流执行都有唯一 correlation ID应在工作流内部基于注入字段自行推导或通过代码构造 ID 后再启动工作流。调度器的运维操作用 CLI 操作调度conductor schedule list conductor schedule pause every-minute-demo-schedule conductor schedule resume every-minute-demo-schedule conductor schedule delete every-minute-demo-schedule用 REST 搜索、暂停与查看执行历史REST 还支持过滤、搜索、暂停原因pause reason以及已调度执行的历史检索# 搜索未暂停的调度每页 20 条 curl http://localhost:8080/api/scheduler/schedules/search?pausedfalsesize20 # 搜索调度执行历史 curl http://localhost:8080/api/scheduler/search/executions?freeTextevery-minute-demo-schedulesize20对应的端点均见 SchedulerResource.java方法路径说明POST/api/scheduler/schedules创建或更新调度GET/api/scheduler/schedules?workflowName列出全部调度可按工作流名过滤GET/api/scheduler/schedules/search搜索调度按名称、工作流、paused 过滤GET/api/scheduler/schedules/{name}按名称获取单个调度DELETE/api/scheduler/schedules/{name}删除调度PUT/api/scheduler/schedules/{name}/pause?reason暂停reason 可选PUT/api/scheduler/schedules/{name}/resume恢复GET/api/scheduler/nextFewSchedules预览未来 N 个执行时间GET/api/scheduler/search/executions搜索调度执行历史PUT/api/scheduler/bulk/pause、/api/scheduler/bulk/resume批量暂停/恢复请求体为调度名 JSON 数组GET/api/scheduler/admin/requeue、/admin/pause、/admin/resume管理员端点作用于调度器内部状态恢复/调试用不是针对单个调度的暂停/恢复应做好访问控制搜索调度的查询参数包括workflowName、scheduleName、paused、freeText默认*、start默认0、size默认100、sort逗号分隔字符串。执行历史搜索额外支持query返回SearchResultWorkflowScheduleExecutionModel执行记录包含调度执行 ID、计划与实际执行时间、工作流名/ID、状态以及失败详情。验证暂停与恢复暂停后检查存储的paused状态为 true并确认下一个 Cron 槽位之后不再出现新的执行恢复后确认产生新的调度执行并检查全部 5 个注入字段是否正确。调度器服务端配置调度器相关配置集中在conductor.scheduler.*对应 SchedulerProperties.java以下是各配置项及其默认值配置项默认值说明conductor.scheduler.enabledtrue是否启用调度器REST 控制器与执行服务装配条件conductor.scheduler.polling-interval100轮询间隔毫秒conductor.scheduler.polling-thread-count1轮询线程数conductor.scheduler.poll-batch-size5每个轮询周期处理的调度数量conductor.scheduler.scheduler-time-zoneUTC服务端调度时区预览端点在此时区求值conductor.scheduler.archival-max-records5每个调度保留的历史记录行数conductor.scheduler.archival-max-record-threshold10超过该阈值时触发清理conductor.scheduler.max-schedule-jitter-ms1000每个调度的派发抖动上限毫秒conductor.scheduler.initial-delay-ms15000启动后的初始延迟毫秒conductor.scheduler.cache-enabledfalse是否启用外部SchedulerCacheDAO加速热路径查询一个典型的 YAML 配置片段conductor: scheduler: enabled: true # default: true polling-interval: 1000 # ms between polls; default: 100 polling-thread-count: 1 # default: 1 poll-batch-size: 5 # schedules processed per cycle; default: 5 scheduler-time-zone: UTC # default: UTC archival-max-records: 5 # history rows to keep per schedule; default: 5 archival-max-record-threshold: 10 # prune when over threshold; default: 10 jitter-max-ms: 0 # dispatch jitter per schedule; default: 0 (disabled)实战提示当大量调度在同一 Cron 时刻触发时应把poll-batch-size提升到与预期扇出fanout匹配的数量例如test-11-thundering-herd.sh要求poll-batch-size N否则默认 5 只能每轮处理 5 个调度并设置较小的jitter-max-ms如 200来平滑对数据库与执行线程池的突发压力。已知限制与设计要点没有原生重叠策略如果前一个工作流仍在运行下一个槽位仍可启动新的执行。并发场景需自行在工作流或下游系统中实现并发控制与幂等策略仓库 concurrent-schedule.json concurrent-workflow.json 即用于演示该行为没有 “run now” 或手动回填端点临时运行请直接启动目标工作流并显式传入预期的窗口参数预览能力受限单 Cron 表达式、最多 5 条、且使用服务端调度时区SDK 一致性Java、Python、TypeScript、Go SDK 可以通过生成式或底层客户端调用 REST 面但本仓库并未在所有 SDK 中定义一致的高层调度器 API请将 REST 视为可移植的完整接口correlationId是字面量不是调度模板。可运行的完整示例场景仓库的 scheduler/examples 目录提供了 8 个经过实测的完整场景每个场景均包含“工作流定义 调度定义”一对文件可直接用于本地验证基础every-minute-schedule.json daily-report-workflow.json——每分钟触发并抓取示例数据集追赶catchup-schedule.json catchup-workflow.json时间窗口bounded-schedule-template.json bounded-workflow.json多步骤 FORK/JOINmultistep-schedule.json multistep-workflow.json注意时区查询参数须用字面量/不要用%2F编码否则 HTTP 任务会被远程 API 拒绝失败场景retry-schedule.json retry-workflow.json——无论上一次执行成败每个槽位都会产生新的调度执行记录并发执行concurrent-schedule.json concurrent-workflow.json注意 WAIT 任务时长须写90s/2m而非 ISO-8601 的PT90S输入参数化input-param-schedule.json input-param-workflow.jsonDO_WHILE 变体dowhile-schedule.json dowhile-workflow.json。一次性初始化示例注册工作流 创建每分钟调度可参考 seed.sh。更完整的可运行教程追赶、窗口、并发、输入、重试、多步骤等菜谱见 scheduled workflow recipes它们复用了上述scheduler/examples/中的文件完整的端点、请求字段、默认值与响应语义则统一收录于 Scheduler API 文档。【免费下载链接】conductorConductor is an event driven agentic workflow engine providing durable and highly resilient execution engine for applications and AI Agents项目地址: https://gitcode.com/GitHub_Trending/co/conductor创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表