快速结论:当 Open WebUI 的 Automation 使用默认 SQLite、且 rrule 未写 DTSTART(典型为每日 06:00、只带 BYHOUR/BYMINUTE)时,dateutil 会用当前墙钟时间锚定规则,使 next_run_at 变成 HH:MM:<当前秒数>;同一分钟内的下一次 scheduler poll 会再次判定为到期,导致同一次计划执行两遍。优先检查 automation 行的 next_run_at 秒数是否非 00,以及日志中是否出现相隔约 10 秒的两次 “Claimed … due automation(s)”。
适用环境:Open WebUI v0.12.0;Docker 部署;默认 SQLite 数据库;单 uvicorn worker;操作系统 Debian 13;容器未设置 TZ(日志为 UTC,22:00 UTC 对应 06:00 HKT)。Issue 中未提供 Ollama 版本或浏览器信息。
最快修复方案:暂无确认的一步修复方案。Issue 与关联 PR(#32264)仍指向 utils/recurrence.py 的规则锚定逻辑,需修改代码或等修复版本,不能仅靠配置项绕过。
注意事项:该问题为间歇性,多数日子只执行一次,因此“今天没复现”不能说明已解决。手动把 next_run_at 改成整分只能临时消除一次,下一次 claim 仍可能重新写入带秒数的值。Issue 中的根因分析与复现命令来自报告者,修复是否已在 dev 分支或后续版本合入,需要以仓库实际状态确认。
问题场景
在 Open WebUI v0.12.0 中启用 Automations,通过 Docker 部署、使用默认 SQLite 且只有一个 uvicorn worker,创建一条每日 06:00 触发、目标为某个 channel 的 automation。保存后存储的 rrule 变为:
RRULE:FREQ=DAILY;BYHOUR=6;BYMINUTE=0
注意该规则没有 DTSTART,也没有 BYSECOND。到点后,该 automation 在同一个计划分钟内被执行两次,间隔约 10 秒,两次都返回成功,并把输出重复发送到目标 channel。报告者观察到运行时间为 06:00:44 与 06:00:54 HKT,且两次 claim 之间没有 HTTP 请求。
报错原文
issue: Automation can run twice per occurrence on SQLite: unanchored DTSTART inherits wall-clock seconds into next_run_at
Scheduler logs (UTC):
2026-10-11 22:00:44.173 Claimed 1 due automation(s)
2026-10-11 22:00:54.208 Claimed 1 due automation(s)
Observed output:
wall now = 2026-10-12T21:10:27+08:00
next occ = 2026-10-13T06:00:27+08:00 # the :27 equals the wall-clock second
原因分析
报告者给出的根因是:utils/recurrence.py::_parse_rule 调用 rrulestr(s, ignoretz=True)。当规则既没有 DTSTART 也没有 BYSECOND 时,dateutil 会把 _dtstart 锚定到 datetime.datetime.now()(微秒清零、秒数保留)。对于 FREQ=DAILY,解析后的规则被原样返回,于是每个 occurrence 都继承 dtstart 的秒数,而 BYHOUR/BYMINUTE 只固定小时和分钟,最终 occurrence 变成 06:00:<claim 时的秒数>。
于是 claim_due 把“当前分钟、当前秒数”的值写入 next_run_at,约 10 秒后的下一次 scheduler poll 仍满足 next_run_at <= now,该行再次被 claim 并执行。等 poll 时间越过这一分钟后,BYMINUTE=0 的候选已落在过去,规则才滚动到下一天,因此重复通常只发生两次就停止。相关 issue #27780 也指出缺少 DTSTART 时 dateutil 在每次 claim 时重新锚定规则,属于同一底层问题。
环境排查
- 确认 Open WebUI 版本是否为 v0.12.0。
- 确认部署方式是否为 Docker,以及是否使用默认 SQLite 数据库。
- 确认 uvicorn worker 数量是否为单个(报告环境为单 worker)。
- 确认宿主/容器操作系统,报告环境为 Debian 13。
- 确认容器是否设置 TZ;报告环境容器无 TZ,日志以 UTC 输出。
- 确认 automation 的 rrule 是否缺少 DTSTART 和 BYSECOND,例如
RRULE:FREQ=DAILY;BYHOUR=6;BYMINUTE=0。 - Issue 中未提供 Python、CUDA、PyTorch、显卡或 Ollama 版本,这些不是本问题的排查项。
解决步骤
- 先确认现象与规则:在容器内执行报告者提供的复现命令,检查
next occ的秒数是否等于执行时刻的墙钟秒数。docker exec open-webui python3 -c " import asyncio, datetime from zoneinfo import ZoneInfo from open_webui.utils.recurrence import next_run_ns tz = ZoneInfo('Asia/Hong_Kong') now = datetime.datetime.now(tz) ns = asyncio.run(next_run_ns('RRULE:FREQ=DAILY;BYHOUR=6;BYMINUTE=0', tz='Asia/Hong_Kong')) print('wall now =', now.isoformat()) print('next occ =', datetime.datetime.fromtimestamp(ns/1e9, tz).isoformat()) "如果
next occ显示06:00:27这类非 00 秒,即符合本 issue 描述的锚定缺陷。 - 检查 scheduler 日志里同一分钟内是否出现两条
Claimed 1 due automation(s),以及 automation_run 是否产生两条 success 记录(HKT 下如同为 06:00:44 和 06:00:54)。 - 检查 automation 行的
next_run_at是否是非整分秒数(例如带有漂移后的 :54)。 - 确认这是代码层问题后,暂无已验证的一步修复方案。可优先尝试关注或合入 PR #32264 对应的 recurrence 锚定修复,而不是反复调整 automation 配置。
- 在等待修复期间,可临时把 next_run_at 手工改为整分(如 06:00:00)以减少下一次重复触发;但下一次 claim 仍可能重新写入带秒数的值,因此这只是权宜处理,Issue 中并未将其作为验证过的方案。
- 若维护方确认 dev 分支已修复合入,升级到包含该修复的版本后再复测。
验证方法
用上述复现命令确认输出变为 06:00:00;到触发日后检查 scheduler 日志,同一分钟内只出现一条 Claimed 1 due automation(s);automation_run 只有一条 success 记录;目标 channel 只收到一次输出;automation 行的 next_run_at 为第二天 06:00:00,且不带执行时的墙钟秒数。由于问题本身是间歇性的,建议连续观察多个触发日,而不只看一次运行。
参考来源
关联 PR:open-webui/open-webui #32264
AI 工具推荐
想把多个 AI 模型放在一个入口?
GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。
推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。
这个方案解决了吗?
可以继续搜索完整报错,或查看同一工具的其他排查指南。


