fix(cron): prevent concurrent cron execution and queue properly

- Add queue-based cron processing in nonInteractiveCli for sequential execution
- Block cron processing while user prompt is active in Session
- Drain cron queue after prompt completion to process queued jobs
- Reduce recurring task auto-expiry from 7 days to 3 days

This fixes race conditions where cron jobs could fire during active prompts
and ensures cron prompts are processed sequentially.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
tanzhenxin 2026-03-30 19:49:17 +08:00
parent dbc86e7672
commit 05f38543cf
6 changed files with 32 additions and 15 deletions

View file

@ -55,7 +55,7 @@ Supported suffixes: `s` (seconds, rounded up to nearest minute, min 1), `m` (min
- `cron`: the expression from the table above
- `prompt`: the parsed prompt from above, verbatim (slash commands are passed through unchanged)
- `recurring`: `true`
2. Briefly confirm: what's scheduled, the cron expression, the human-readable cadence, that recurring tasks auto-expire after 7 days, and that they can cancel sooner with CronDelete (include the job ID).
2. Briefly confirm: what's scheduled, the cron expression, the human-readable cadence, that recurring tasks auto-expire after 3 days, and that they can cancel sooner with CronDelete (include the job ID).
3. **Then immediately execute the parsed prompt now** — don't wait for the first cron fire. If it's a slash command, invoke it via the Skill tool; otherwise act on it directly.
## Input

View file

@ -33,7 +33,7 @@ describe('CronCreateTool', () => {
const result = await invocation.execute(new AbortController().signal);
expect(result.error).toBeUndefined();
expect(result.llmContent).toContain('Scheduled recurring job');
expect(result.llmContent).toContain('Auto-expires after 7 days');
expect(result.llmContent).toContain('Auto-expires after 3 days');
expect(config._scheduler.list()).toHaveLength(1);
});

View file

@ -52,7 +52,7 @@ class CronCreateInvocation extends BaseToolInvocation<
llmContent =
`Scheduled recurring job ${job.id} (${job.cronExpr}). ` +
'Session-only (not written to disk, dies when Qwen Code exits). ' +
'Auto-expires after 7 days. Use CronDelete to cancel sooner.';
'Auto-expires after 3 days. Use CronDelete to cancel sooner.';
} else {
llmContent =
`Scheduled one-shot task ${job.id} (${job.cronExpr}). ` +