Skip to content

fix(cron): preserve fixed scheduling intervals - #10373

Open
ArcueidMP wants to merge 5 commits into
AstrBotDevs:masterfrom
ArcueidMP:fix/10363-fixed-interval
Open

ArcueidMP wants to merge 5 commits into
AstrBotDevs:masterfrom
ArcueidMP:fix/10363-fixed-interval

Conversation

@ArcueidMP

@ArcueidMP ArcueidMP commented Oct 4, 2026 •

Copy link
Copy Markdown

Fixes #10363.

The WebUI converted fixed intervals into Cron field steps, so “every 40 minutes” ran at alternating 40/20-minute gaps, 60 minutes became 59/1, and 24 hours became 23/1. Interval tasks now use APScheduler's IntervalTrigger with a persisted UTC anchor.

Modifications

  • Add nullable interval_seconds and interval_anchor_at columns with an idempotent SQLite migration. Existing jobs retain their Cron expressions and schedules.

  • Run new interval jobs after one full interval. Restart and enable/disable preserve their phase and skip missed periods. Editing metadata keeps the anchor; changing the duration resets it. A day means 24 elapsed hours, including across DST.

  • Validate whole-minute intervals and reject invalid, oversized, or conflicting schedules before persistence, including disabled jobs. Both API families support explicitly clearing an interval when changing schedule types.

  • Submit structured intervals from the WebUI. Legacy */N jobs display and reopen as Custom Cron rather than promising a fixed interval.

  • Regenerate the API client and update the Chinese/English instructions, including the current Extensions → Future Tasks navigation and migration guidance. Replace the outdated task screenshot with complete text instructions.

  • This is not a breaking change for existing schedules.

Verification steps and test results

  • Python suite: 3790 passed, 5 skipped using bash scripts/run_pytests_ci.sh tests -q with an isolated temporary test directory.
  • Frontend suite: 75 passed using node --test dashboard/tests/*.test.mjs.
  • Regression coverage: 40/60-minute and 24-hour intervals; month/DST boundaries; restart phase and missed periods; edits, toggles, and schedule-type switches; invalid inputs; legacy database migration; hosts without an IANA timezone database.
  • uv run ruff format ., uv run ruff check ., and all configured pre-commit hooks passed.
  • pnpm --dir dashboard build and pnpm --dir docs docs:build passed.
  • Browser smoke check against the built WebUI and a temporary runtime: created/reopened a 40-minute task, edited its note without changing the next run, and confirmed a legacy */40 * * * * schedule is labeled Custom Cron. No live model or messaging credentials were configured.

Checklist

Summary by Sourcery

Preserve fixed scheduling intervals by storing UTC anchors and running them with elapsed-time interval triggers instead of Cron field steps.

New Features:

  • Add fixed-duration interval scheduling backed by persisted UTC anchors, preserving elapsed timing across restarts, toggles, edits, missed periods, and daylight-saving transitions.
  • Expose interval schedules through both APIs and the WebUI, including explicit schedule-type switching and interval clearing.

Bug Fixes:

  • Prevent fixed intervals such as 40 minutes, 60 minutes, and 24 hours from being converted into inaccurate Cron field steps.
  • Preserve existing Cron schedules during migration and display legacy step-based jobs as Custom Cron.

Enhancements:

  • Validate interval values and reject conflicting or invalid schedules before persistence.
  • Add idempotent SQLite schema migration for interval metadata.
  • Update English and Chinese scheduling guidance and regenerate the API client.

Documentation:

  • Document fixed-interval behavior, lifecycle semantics, DST handling, API representation, and legacy schedule migration.

Tests:

  • Add regression coverage for interval timing, persistence, restart behavior, schedule switching, validation, API round trips, frontend behavior, and legacy database migration.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="astrbot/core/cron/manager.py" line_range="189" />
<code_context>
         persistent: bool = True,
         run_once: bool = False,
         run_at: datetime | None = None,
+        interval_seconds: int | None = None,
     ) -> CronJob:
         # If run_once with run_at, store run_at in payload for later reference.
</code_context>
<issue_to_address>
**issue (bug_risk):** The new interval capability is not propagated to the built-in future-task tool: its create and edit paths still require a Cron expression and never pass `interval_seconds`. An interval task created through the WebUI therefore cannot be edited through the agent tool, even for metadata-only changes, because the tool rejects it with `cron_expression is required when run_once=false`.

**Triggers:** When an interval task is edited through the built-in future-task tool.

**Suggested fix:** Teach the tool's create/edit validation and update payloads about `interval_seconds`, or explicitly reject interval tasks with a clear unsupported-schedule error.
</issue_to_address>

Sourcery assessment

Needs a human reviewer. 1 finding to address first, and this changes persisted scheduling state and the production scheduler, so an incorrect interval or anchor could cause active-agent jobs to run at the wrong times and send task results or other notifications before the change is reverted. Reverting restores the old scheduling code, but it cannot undo jobs that already ran or messages that were already sent.

Blocking findings: astrbot/core/cron/manager.py:189


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread astrbot/core/cron/manager.py
@ArcueidMP

Copy link
Copy Markdown
Author

Addressed the Sourcery finding in 0226878:

  • Editing only the name or note of an interval task through future_task now keeps its interval and anchor instead of failing with cron_expression is required when run_once=false.
  • Setting a Cron expression or a one-time run_at through the tool clears the interval, so schedule types never combine.
  • test_future_task_tool_edits_interval_job drives the real tool against the real SQLite store and scheduler; both cases failed before this fix.

@Soulter Is there anything else needed for this PR?

…nterval

# Conflicts:
#	docs/en/use/proactive-agent.md
#	docs/zh/use/proactive-agent.md
@ArcueidMP

Copy link
Copy Markdown
Author

@LIghtJUNction This implements the approach from your analysis in #10363 and is now conflict-free with master. Most of the diff is tests (~510 of ~830 lines); production changes are ~270 lines. Could a maintainer approve the CI run and take a look when convenient? Thanks!

@ArcueidMP

Copy link
Copy Markdown
Author

@RC-CHN @anka-afk This fixes #10363 by scheduling fixed intervals with IntervalTrigger and a persisted UTC anchor; existing */N jobs keep their Cron schedules. It touches cron_service.py and the timezone handling from #9579, so a review from someone familiar with that area would help. The Sourcery finding is addressed, and the PR is still conflict-free with master after #10549. As a first-time contributor, my CI workflows are still awaiting approval. Could a maintainer approve the run and take a look when convenient? Thanks!

…nterval

# Conflicts:
#	astrbot/core/cron/manager.py
@ArcueidMP

Copy link
Copy Markdown
Author

Friendly ping: the CI workflows for this PR are still waiting for maintainer approval ("action_required"), so they have not run yet. The branch is up to date with the latest master and has no conflicts. Could a maintainer please approve the workflow run? Thanks!

@ArcueidMP

Copy link
Copy Markdown
Author

@Soulter Could you approve the CI workflow run for this PR when you have a moment? Thanks!

…nterval

# Conflicts:
#	astrbot/core/cron/manager.py

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] 定时间隔未按固定间隔执行:每 60 分钟变为 59/1 分钟交替,每 24 小时变为 23/1 小时交替

1 participant