Skip to content

[错误报告]: 订阅日历缓存任务完成后进度状态残留 running,前端持续显示「进行中」 #6479

Description

@fock512

确认

  • 我的版本是最新版本,我的版本号与 version 相同。
  • 我已经 issue 中搜索过,确认我的问题没有被提出过。
  • 我已经 Telegram频道 中搜索过,确认我的问题没有被提出过。
  • 我已经修改标题,将标题中的 描述 替换为我遇到的问题。

当前程序版本

v3.0.0

运行环境

Docker

问题类型

主程序运行问题

问题描述

现象

  • 订阅日历缓存 定时任务实际执行完成后,进度状态仍残留为 runningenable=Truestatus=runningfinished_at=null),前端一直显示「进行中」转圈状态。
  • 手动清除 Redis 中的残留进度缓存后界面恢复为「等待」,但任务再次执行后问题会复发。

复现步骤

  1. 触发 订阅日历缓存 定时任务(scheduler: subscribe_calendar_cache)。
  2. 等待任务执行完成(日志显示「订阅日历预缓存完成」)。
  3. 查看该任务的进度状态,status 仍为 running,前端持续显示「进行中」。

期望行为

  • 任务执行完成后,进度状态应正确更新为完成(enable=Falsestatus=success),前端不再显示「进行中」。

已定位 / 推测

  • 这是一个 read-modify-write 竞态条件问题,发生在两个并发异步任务之间:
    1. cache_calendar 在结束时调用 progress_callback(value=100, text=订阅日历预缓存完成),该回调被提交到事件循环执行 _update()
    2. 同时 __run_coro_jobfinally 块调用 __finish_job,其内部执行 AsyncProgressHelper.end()
    3. 两者都执行「读取 Redis -> 修改数据 -> 写回 Redis」的操作,并发交错时后写的一方会覆盖先写的数据:
      • end() 读取到 enable=True
      • _update() 也读取到 enable=True
      • end() 设置 enable=Falsestatus=success
      • _update() 设置 value=100text=...status=running
      • end() 写回 Redis
      • _update() 写回 Redis,覆盖了 end() 的数据
    4. 最终结果:enable=True_update() 不修改该字段)、status=running,即残留的「进行中」状态。

建议修复方案

  • AsyncProgressHelper 中使用 Redis 事务或 Lua 脚本,保证 update()end() 的「读取-修改-写回」操作原子性;
  • 或者,在 __build_progress_callback 中当 value=100 时不再更新进度状态,避免与 __finish_jobend() 冲突。

已尝试的处理

  • 已清除 Redis 中的残留进度缓存,界面恢复为「等待」,但问题会随任务再次执行而复发,属于需要上游修复的代码缺陷。

发生问题时系统日志和配置文件

### Doctor 摘要
状态:degraded
运行环境:Docker
汇总:total=13 error=0 warn=1 advisory=1 fixed=0
关键发现:
- [warn] 最近日志存在错误线索;来源:moviepilot.log;命中:3 条;建议:结合前后的启动日志定位异常;必要时执行 `moviepilot doctor --json` 交给 Agent 或 Issue 流程。

### 日志筛选依据
策略:time_window_and_keyword_block_match
时间窗口:最近 1440 分钟
窗口起点:2026-08-26T11:21:32
关键词:AsyncProgressHelper、cache_calendar、订阅日历
单文件最多保留:80 行
命中文件:
- /config/logs/moviepilot.log;命中关键词:AsyncProgressHelper、cache_calendar、订阅日历;行数:80

### moviepilot.log
【INFO】2026-08-26 14:57:23,117 [fc6bbf7545e144f0bb4a355ef433322f] - message.py - 发送消息:{'message': Message(channel=<NotificationChannel.Wechat: '微信'>, source='企业微信', mtype=<MessageType.Agent: '智能体'>, ctype=None, title='', text='⚙️ => 执行系统命令: grep -n "订阅日历缓存\\|cache_calendar\\|预缓存订阅日历" /config/logs/moviepilot.log | grep -v "message.py\\|orchestrator.py\\|base.py\\|execute_command.py" | tail -20', image=None, voice_path=None, file_path=None, file_name=None, voice_caption=None, link=None, userid=<REDACTED>', username=<REDACTED>', date=None, action=1, targets=None, buttons=None, force_reply=False, original_message_id=None, original_chat_id=None, private_delivery=False, disable_web_page_preview=None, parse_mode=None, rich_message=None, save_history=False), 'current_time': '2026-08-26 14:57:23'}
【INFO】2026-08-26 14:57:23,437 [fc6bbf7545e144f0bb4a355ef433322f] - execute_command.py - 执行工具: execute_command, action=run, command=grep -n "订阅日历缓存\|cache_calendar\|预缓存订阅日历" /config/logs/moviepilot.log | grep -v "message.py\|orchestrator.py\|base.py\|execute_command.py" | tail -20, session_id=<REDACTED>
【INFO】2026-08-26 14:57:03,095 [fc6bbf7545e144f0bb4a355ef433322f] - subscribe.py - 开始预缓存订阅日历 ...
【INFO】2026-08-26 14:57:03,096 [fc6bbf7545e144f0bb4a355ef433322f] - base.py - Agent工具 run_scheduler 执行完成,结果摘要: 成功触发定时服务:订阅日历缓存 (ID: subscribe_calendar_cache)
【INFO】2026-08-26 14:57:03,098 [fc6bbf7545e144f0bb4a355ef433322f] - orchestrator.py - Agent工具执行完成: tool=run_scheduler, origin=agent_interactive, shadow=True, duration_ms=309, result=成功触发定时服务:订阅日历缓存 (ID: subscribe_...
【INFO】2026-08-26 14:57:03,095 [fc6bbf7545e144f0bb4a355ef433322f] - subscribe.py - 开始预缓存订阅日历 ...
【INFO】2026-08-26 14:57:03,096 [fc6bbf7545e144f0bb4a355ef433322f] - base.py - Agent工具 run_scheduler 执行完成,结果摘要: 成功触发定时服务:订阅日历缓存 (ID: subscribe_calendar_cache)
【INFO】2026-08-26 14:57:03,098 [fc6bbf7545e144f0bb4a355ef433322f] - orchestrator.py - Agent工具执行完成: tool=run_scheduler, origin=agent_interactive, shadow=True, duration_ms=309, result=成功触发定时服务:订阅日历缓存 (ID: subscribe_...
【INFO】2026-08-26 14:57:31,689 [fc6bbf7545e144f0bb4a355ef433322f] - message.py - 发送消息:{'message': Message(channel=<NotificationChannel.Wechat: '微信'>, source='企业微信', mtype=<MessageType.Agent: '智能体'>, ctype=None, title='', text='⚙️ => 执行系统命令: rg -n "subscribe_calendar_cache\\|订阅日历缓存" /app/app/api --type py', image=None, voice_path=None, file_path=None, file_name=None, voice_caption=None, link=None, userid=<REDACTED>', username=<REDACTED>', date=None, action=1, targets=None, buttons=None, force_reply=False, original_message_id=None, original_chat_id=None, private_delivery=False, disable_web_page_preview=None, parse_mode=None, rich_message=None, save_history=False), 'current_time': '2026-08-26 14:57:31'}
【INFO】2026-08-26 14:57:31,981 [fc6bbf7545e144f0bb4a355ef433322f] - execute_command.py - 执行工具: execute_command, action=run, command=rg -n "subscribe_calendar_cache\|订阅日历缓存" /app/app/api --type py, session_id=<REDACTED>
【INFO】2026-08-26 14:57:46,253 [fc6bbf7545e144f0bb4a355ef433322f] - message.py - 发送消息:{'message': Message(channel=<NotificationChannel.Wechat: '微信'>, source='企业微信', mtype=<MessageType.Agent: '智能体'>, ctype=None, title='', text='⚙️ => 执行系统命令: python3 -c "\nimport asyncio\nfrom app.runtime.progress import AsyncProgressHelper\n\nasync def check():\n    p = AsyncProgressHelper(\'scheduler:subscribe_calendar_cache\')\n    val = await p.get()\n    print(\'Progress:\', val)\n\nasyncio.run(check())\n"', image=None, voice_path=None, file_path=None, file_name=None, voice_caption=None, link=None, userid=<REDACTED>', username=<REDACTED>', date=None, action=1, targets=None, buttons=None, force_reply=False, original_message_id=None, original_chat_id=None, private_delivery=False, disable_web_page_preview=None, parse_mode=None, rich_message=None, save_history=False), 'current_time': '2026-08-26 14:57:46'}
【INFO】2026-08-26 14:58:54,603 [fc6bbf7545e144f0bb4a355ef433322f] - message.py - 发送消息:{'message': Message(channel=<NotificationChannel.Wechat: '微信'>, source='企业微信', mtype=<MessageType.Agent: '智能体'>, ctype=None, title='', text='已手动触发了一次 `订阅日历缓存` 任务,后台日志显示它在 15 毫秒内就执行完成了,状态正常。\n\n当前后端状态:\n- 任务状态:等待\n- 下次运行:约 6 小时后\n- 无卡住的进程\n- Redis/缓存中无残留的进度数据\n\nWeb 界面显示"一直在转圈"是前端状态显示问题,不是任务真的在运行。\n\n请尝试以下操作:\n\n1. 刷新浏览器页面(按 F5 或 Ctrl+R)\n2. 如果刷新无效,尝试清除浏览器缓存后重新打开(Ctrl+Shift+Delete 清除缓存)\n3. 或者换一个浏览器/无痕模式打开 MoviePilot 查看\n\n如果刷新后仍然显示为运行中,请截图发给我,我会进一步排查前端状态同步的问题。', image=None, voice_path=None, file_path=None, file_name=None, voice_caption=None, link=None, userid=<REDACTED>', username=<REDACTED>', date=None, action=1, targets=None, buttons=None, force_reply=False, original_message_id=None, original_chat_id=None, private_delivery=False, disable_web_page_preview=None, parse_mode=None, rich_message=None, save_history=False), 'current_time': '2026-08-26 14:58:54'}
【INFO】2026-08-26 14:58:54,583 [fc6bbf7545e144f0bb4a355ef433322f] - callback - Agent消息: 已手动触发了一次 `订阅日历缓存` 任务,后台日志显示它在 15 毫秒内就执行完成了,状态正常。
当前后端状态:
- 任务状态:等待
- 下次运行:约 6 小时后
- 无卡住的进程
- Redis/缓存中无残留的进度数据
Web 界面显示"一直在转圈"是前端状态显示问题,不是任务真的在运行。
请尝试以下操作:
1. 刷新浏览器页面(按 F5 或 Ctrl+R)
2. 如果刷新无效,尝试清除浏览器缓存后重新打开(Ctrl+Shift+Delete 清除缓存)
3. 或者换一个浏览器/无痕模式打开 MoviePilot 查看
如果刷新后仍然显示为运行中,请截图发给我,我会进一步排查前端状态同步的问题。
【INFO】2026-08-26 15:04:24,587 [95c720923d994639bc5f80bf683ffeb4] - message.py - 发送消息:{'message': Message(channel=<NotificationChannel.Wechat: '微信'>, source='企业微信', mtype=<MessageType.Agent: '智能体'>, ctype=None, title='', text='已定位并修复问题。\n\n**原因:** Redis 缓存中残留了一条错误的进度数据,其中 `status` 为 `"running"` 且 `finished_at` 为 `null`,导致前端持续显示为运行中。虽然任务实际早已执行完成,但进度状态没有正确更新。\n\n**已处理:** 清除了 Redis 中的残留进度缓存。\n\n现在请刷新 MoviePilot 页面,"订阅日历缓存" 应该显示为"等待"状态了。', image=None, voice_path=None, file_path=None, file_name=None, voice_caption=None, link=None, userid=<REDACTED>', username=<REDACTED>', date=None, action=1, targets=None, buttons=None, force_reply=False, original_message_id=None, original_chat_id=None, private_delivery=False, disable_web_page_preview=None, parse_mode=None, rich_message=None, save_history=False), 'current_time': '2026-08-26 15:04:24'}
【INFO】2026-08-26 15:05:01,648 [3ec6f8f5d5154013a638de66194791fc] - wechat - 收到来自 企业微信 的微信消息:userid=<REDACTED> text=刷新 MoviePilot 页面,"订阅日历缓存" 显示为"等待"状态
【INFO】2026-08-26 20:50:14,710 [-] - subscribe.py - 开始预缓存订阅日历 ...
【INFO】2026-08-26 20:50:14,825 [-] - subscribe.py - 订阅日历预缓存完成
【INFO】2026-08-27 02:50:14,710 [-] - subscribe.py - 开始预缓存订阅日历 ...
【INFO】2026-08-27 02:50:14,813 [-] - subscribe.py - 订阅日历预缓存完成
【INFO】2026-08-27 08:50:14,709 [-] - subscribe.py - 开始预缓存订阅日历 ...
【INFO】2026-08-27 08:50:14,797 [-] - subscribe.py - 订阅日历预缓存完成
【INFO】2026-08-27 10:34:20,493 [ab26b6a49aae41c7b8dc427d34a0eb4f] - wechat - 收到来自 企业微信 的微信消息:userid=<REDACTED> text=今天刷新 MoviePilot 页面,"订阅日历缓存" 又显示为"进行中"转圈状态,难道又是Redis 缓存中残留了一条状态为 `running``finished_at``null` 的进度数据,导致前端持续显示为运行中?
【INFO】2026-08-27 10:34:45,217 [ab26b6a49aae41c7b8dc427d34a0eb4f] - message.py - 发送消息:{'message': Message(channel=<NotificationChannel.Wechat: '微信'>, source='企业微信', mtype=<MessageType.Agent: '智能体'>, ctype=None, title='', text='⚙️ => 执行系统命令: grep -n "订阅日历缓存\\|cache_calendar\\|预缓存订阅日历" /config/logs/moviepilot.log | grep -v "message.py\\|orchestrator.py\\|base.py\\|execute_command.py" | tail -20', image=None, voice_path=None, file_path=None, file_name=None, voice_caption=None, link=None, userid=<REDACTED>', username=<REDACTED>', date=None, action=1, targets=None, buttons=None, force_reply=False, original_message_id=None, original_chat_id=None, private_delivery=False, disable_web_page_preview=None, parse_mode=None, rich_message=None, save_history=False), 'current_time': '2026-08-27 10:34:45'}
【INFO】2026-08-27 10:34:45,509 [ab26b6a49aae41c7b8dc427d34a0eb4f] - execute_command.py - 执行工具: execute_co
...(已截断)

本 Issue 由 MoviePilot Agent 协助用户提交。

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions