feat(queue): 新增循环队列模式 - #268
Open
qiyinxi wants to merge 5 commits into
Open
Conversation
审阅者指南为队列实现新的 CycleRun 模式,用于按队列项的循环计划执行;新增后端计划/数据字段和调度逻辑,用于持续执行与预览;更新队列/定时器行为以区分“定时队列”和“循环队列”;并新增前端 UI,用于配置循环计划、启动循环运行、预览即将运行的任务,以及在循环队列运行期间锁定编辑操作。 CycleRun 队列执行与预览的时序图sequenceDiagram
actor User
participant SchedulerUI as SchedulerCenter
participant TaskManager as TaskManager.add_task
participant Task as Task.main_task
participant QueueCycle as collect_queue_cycle_entries
User->>SchedulerUI: startTask(tab) with mode = CycleRun
SchedulerUI->>TaskManager: add_task(mode="CycleRun", id=selectedTaskId)
TaskManager-->>SchedulerUI: task_uid
TaskManager->>Task: execute() -> main_task()
Task->>Task: prepare()
Task->>Task: _run_cycle_task()
Task->>Task: _run_cycle_loop(queue_uid)
loop cycle loop
Task->>QueueCycle: collect_queue_cycle_entries(queue, ScriptConfig, now)
QueueCycle-->>Task: entries
Task->>Task: _set_cycle_preview(entries)
alt entries due
Task->>Task: _run_cycle_script(queue_uid, entry,...)
Task->>QueueCycle: calculate_next_after_start/finish()
Task->>Task: _refresh_cycle_preview(queue_uid)
else no due entries
Task->>Task: asyncio.sleep(wait_seconds)
end
end
文件级变更
提示与命令与 Sourcery 交互
自定义使用体验打开你的 dashboard 以:
获取帮助Original review guide in EnglishReviewer's GuideImplements a new CycleRun mode for queues with per-item recurring schedules, adds backend schedule/data fields and scheduler logic for continuous execution and preview, updates queue/timer behavior to distinguish timed vs cycle queues, and introduces frontend UI for configuring cycle schedules, starting cycle runs, previewing upcoming runs, and locking editing while a cycle queue is running. Sequence diagram for CycleRun queue execution and previewsequenceDiagram
actor User
participant SchedulerUI as SchedulerCenter
participant TaskManager as TaskManager.add_task
participant Task as Task.main_task
participant QueueCycle as collect_queue_cycle_entries
User->>SchedulerUI: startTask(tab) with mode = CycleRun
SchedulerUI->>TaskManager: add_task(mode="CycleRun", id=selectedTaskId)
TaskManager-->>SchedulerUI: task_uid
TaskManager->>Task: execute() -> main_task()
Task->>Task: prepare()
Task->>Task: _run_cycle_task()
Task->>Task: _run_cycle_loop(queue_uid)
loop cycle loop
Task->>QueueCycle: collect_queue_cycle_entries(queue, ScriptConfig, now)
QueueCycle-->>Task: entries
Task->>Task: _set_cycle_preview(entries)
alt entries due
Task->>Task: _run_cycle_script(queue_uid, entry,...)
Task->>QueueCycle: calculate_next_after_start/finish()
Task->>Task: _refresh_cycle_preview(queue_uid)
else no due entries
Task->>Task: asyncio.sleep(wait_seconds)
end
end
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
qiyinxi
marked this pull request as ready for review
June 27, 2026 15:11
There was a problem hiding this comment.
Hey - 我发现了 1 个问题,并且有一些整体性的反馈:
- TaskManager 和 Config 都在跟踪 running_cycle_queue_ids,但更新逻辑分散在多个地方;建议把这块状态管理集中起来(例如把队列运行的相关簿记封装成一个单独的 helper),以避免两处状态之间出现细微且难以排查的不一致。
- Task._run_cycle_loop 中与 cycle-run 相关的路径已经变得非常庞大,并且混合了调度、冲突处理、日志记录和预览更新等逻辑;建议拆分成更小、更聚焦的 helpers(例如:计算到期条目、更新 NextRunAt、处理失败等),以便让控制流更容易理解和维护。
给 AI Agents 的提示词
Please address the comments from this code review:
## Overall Comments
- TaskManager 和 Config 都在跟踪 running_cycle_queue_ids,但更新逻辑分散在多个地方;建议把这块状态管理集中起来(例如把队列运行的相关簿记封装成一个单独的 helper),以避免两处状态之间出现细微且难以排查的不一致。
- Task._run_cycle_loop 中与 cycle-run 相关的路径已经变得非常庞大,并且混合了调度、冲突处理、日志记录和预览更新等逻辑;建议拆分成更小、更聚焦的 helpers(例如:计算到期条目、更新 NextRunAt、处理失败等),以便让控制流更容易理解和维护。
## Individual Comments
### Comment 1
<location path="frontend/src/views/scheduler/SchedulerTaskControl.vue" line_range="172-173" />
<code_context>
// 模式选项
const modeOptions = TASK_MODE_OPTIONS
+const isQueueOption = (option?: ComboBoxItem | null) => {
+ return Boolean(option?.label?.startsWith('队列 - '))
+}
+
</code_context>
<issue_to_address>
**suggestion (bug_risk):** 使用 label 前缀启发式来识别队列任务比较脆弱;可以考虑使用显式标记或约定的 value 模式。
`isQueueOption` 目前完全依赖 `"队列 - "` 这个 label 前缀来推断队列选项,而这个结果同时影响 cycle 模式过滤以及是否显示“恢复脚本”下拉框。把逻辑耦合到用户可见的文案上比较危险(本地化、文案调整或重命名都会在没有任何提示的情况下改变行为)。
更推荐使用更稳定的信号,例如在 option 上增加一个显式字段(`kind: 'queue' | 'script'`),或使用 value 的某个稳定特征(例如属于 `QueueConfig`)。如果暂时无法调整 API,至少可以把这一假设集中到一个地方并清晰注释,以降低未来修改 label 文案时误伤这段逻辑的风险。
Suggested implementation:
```
// 本地状态,用于双向绑定
const localSelectedTaskId = ref(props.selectedTaskId)
const localSelectedMode = ref(props.selectedMode)
// 模式选项
const modeOptions = TASK_MODE_OPTIONS
// 队列任务识别相关:优先使用稳定信号,其次才回退到 label 前缀的启发式
// - 推荐:在 ComboBoxItem 上增加 `kind: 'queue' | 'script' | ...` 字段
// - 备选:统一使用 `value` 前缀(例如 `queue:`)标识队列任务
// - 最后:为了兼容旧数据,保留对「队列 - 」label 前缀的回退逻辑
const QUEUE_LABEL_PREFIX = '队列 - '
const isQueueOption = (option?: ComboBoxItem | null) => {
if (!option) return false
// 1. 显式类型标记(推荐方式)
if ((option as any).kind === 'queue') return true
// 2. value 约定前缀(例如后端约定队列任务值以 `queue:` 开头)
if (typeof (option as any).value === 'string' && (option as any).value.startsWith('queue:')) {
return true
}
// 3. 兼容旧逻辑:仅在上述信号都不存在时,才使用 label 前缀启发式
return Boolean(option.label?.startsWith(QUEUE_LABEL_PREFIX))
}
interface Props {
```
1. **如果还没有显式标记:** 在构造 `ComboBoxItem` 的地方(通常是任务列表、队列配置映射处),为队列任务项补充 `kind: 'queue'` 字段,并/或约定队列任务使用 `value` 前缀(如 `queue:${id}`),这样 `isQueueOption` 将依赖这些稳定信号而不是 label 前缀。
2. **全局复用:** 如果其它组件也需要识别队列任务,可以将 `QUEUE_LABEL_PREFIX` 和 `isQueueOption` 抽到一个共享的 util(例如 `@/views/scheduler/utils/taskOption.ts`),并在本组件中按约定路径导入,以消除重复逻辑。
</issue_to_address>帮我变得更有用!请对每条评论点 👍 或 👎,我会根据这些反馈改进后续的代码评审。
Original comment in English
Hey - I've found 1 issue, and left some high level feedback:
- TaskManager and Config both track running_cycle_queue_ids, but updates are split across several places; consider centralizing this state management (e.g., encapsulating queue-running bookkeeping in a single helper) to avoid subtle inconsistencies between the two sets.
- The cycle-run path in Task._run_cycle_loop has grown quite large and mixes scheduling, conflict handling, logging, and preview updates; consider breaking it into smaller, focused helpers (e.g. for computing due entries, updating NextRunAt, and handling failures) to make the control flow easier to reason about and maintain.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- TaskManager and Config both track running_cycle_queue_ids, but updates are split across several places; consider centralizing this state management (e.g., encapsulating queue-running bookkeeping in a single helper) to avoid subtle inconsistencies between the two sets.
- The cycle-run path in Task._run_cycle_loop has grown quite large and mixes scheduling, conflict handling, logging, and preview updates; consider breaking it into smaller, focused helpers (e.g. for computing due entries, updating NextRunAt, and handling failures) to make the control flow easier to reason about and maintain.
## Individual Comments
### Comment 1
<location path="frontend/src/views/scheduler/SchedulerTaskControl.vue" line_range="172-173" />
<code_context>
// 模式选项
const modeOptions = TASK_MODE_OPTIONS
+const isQueueOption = (option?: ComboBoxItem | null) => {
+ return Boolean(option?.label?.startsWith('队列 - '))
+}
+
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Using label prefix heuristics to detect queue tasks is brittle; consider an explicit flag or value pattern.
`isQueueOption` currently infers queue options solely from the `"队列 - "` label prefix, and that result drives both cycle-mode filtering and whether the resume-script select is shown. This coupling to user-visible text is fragile (localization, copy changes, or renames will silently change behavior).
Prefer a more stable signal, e.g. an explicit field on the option (`kind: 'queue' | 'script'`) or a reliable property of the value (e.g. membership in `QueueConfig`). If the API can’t change yet, at least centralize and clearly document this assumption in one place to reduce the risk of future label refactors breaking this logic.
Suggested implementation:
```
// 本地状态,用于双向绑定
const localSelectedTaskId = ref(props.selectedTaskId)
const localSelectedMode = ref(props.selectedMode)
// 模式选项
const modeOptions = TASK_MODE_OPTIONS
// 队列任务识别相关:优先使用稳定信号,其次才回退到 label 前缀的启发式
// - 推荐:在 ComboBoxItem 上增加 `kind: 'queue' | 'script' | ...` 字段
// - 备选:统一使用 `value` 前缀(例如 `queue:`)标识队列任务
// - 最后:为了兼容旧数据,保留对「队列 - 」label 前缀的回退逻辑
const QUEUE_LABEL_PREFIX = '队列 - '
const isQueueOption = (option?: ComboBoxItem | null) => {
if (!option) return false
// 1. 显式类型标记(推荐方式)
if ((option as any).kind === 'queue') return true
// 2. value 约定前缀(例如后端约定队列任务值以 `queue:` 开头)
if (typeof (option as any).value === 'string' && (option as any).value.startsWith('queue:')) {
return true
}
// 3. 兼容旧逻辑:仅在上述信号都不存在时,才使用 label 前缀启发式
return Boolean(option.label?.startsWith(QUEUE_LABEL_PREFIX))
}
interface Props {
```
1. **如果还没有显式标记:** 在构造 `ComboBoxItem` 的地方(通常是任务列表、队列配置映射处),为队列任务项补充 `kind: 'queue'` 字段,并/或约定队列任务使用 `value` 前缀(如 `queue:${id}`),这样 `isQueueOption` 将依赖这些稳定信号而不是 label 前缀。
2. **全局复用:** 如果其它组件也需要识别队列任务,可以将 `QUEUE_LABEL_PREFIX` 和 `isQueueOption` 抽到一个共享的 util(例如 `@/views/scheduler/utils/taskOption.ts`),并在本组件中按约定路径导入,以消除重复逻辑。
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
摘要
CycleRun调度模式,支持队列按脚本级循环配置持续运行。Summary by Sourcery
为队列引入新的循环运行调度模式,使脚本级的周期性执行支持针对每个队列项的独立计划和 UI 展示。
新功能:
CycleRun任务模式,以持续循环的方式运行队列,并包含冲突处理、重试逻辑和下次运行时间计算。CycleRun模式,包括下一个循环的预览面板,以及过滤功能,确保只有队列可以被选择用于循环运行。缺陷修复:
增强改进:
Original summary in English
Summary by Sourcery
Introduce a new cycle-run scheduling mode for queues, enabling script-level recurring execution with per-item schedules and UI support.
New Features:
Bug Fixes:
Enhancements:
Original summary in English
Summary by Sourcery
为队列引入新的循环运行调度模式,使脚本级的周期性执行支持针对每个队列项的独立计划和 UI 展示。
新功能:
CycleRun任务模式,以持续循环的方式运行队列,并包含冲突处理、重试逻辑和下次运行时间计算。CycleRun模式,包括下一个循环的预览面板,以及过滤功能,确保只有队列可以被选择用于循环运行。缺陷修复:
增强改进:
Original summary in English
Summary by Sourcery
Introduce a new cycle-run scheduling mode for queues, enabling script-level recurring execution with per-item schedules and UI support.
New Features:
Bug Fixes:
Enhancements: