fix: raise default cron concurrency · openclaw/openclaw@bc12e04
steipete
·
2026-05-26
·
via Recent Commits to openclaw:main
| Original file line number | Diff line number | Diff line change |
|---|
@@ -6,6 +6,7 @@ Docs: https://docs.openclaw.ai
|
6 | 6 | |
7 | 7 | ### Changes |
8 | 8 | |
| 9 | +- Cron: default `cron.maxConcurrentRuns` to 8 so scheduled automations and their isolated agent turns can make progress in parallel without explicit configuration. |
9 | 10 | - QA-Lab: add `qa coverage --match <query>` so focused proof selection can discover matching scenarios from existing metadata before running live or remote lanes. |
10 | 11 | - Control UI: add an ephemeral Activity tab for sanitized live tool activity summaries without persisting raw telemetry. Fixes #12831. Thanks @BunsDev. |
11 | 12 | - Build: include `ui:build` in the `full` and `ciArtifacts` profiles of `scripts/build-all.mjs` so `pnpm build` always rebuilds `dist/control-ui` after `tsdown` cleans `dist`, removing the second-command requirement and the missing-asset failure mode for source/runtime installs and CI artifact uploads. (#85206) |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -436,7 +436,7 @@ Model override note:
|
436 | 436 | cron: { |
437 | 437 | enabled: true, |
438 | 438 | store: "~/.openclaw/cron/jobs.json", |
439 | | - maxConcurrentRuns: 1, |
| 439 | + maxConcurrentRuns: 8, |
440 | 440 | retry: { |
441 | 441 | maxAttempts: 3, |
442 | 442 | backoffMs: [60000, 120000, 300000], |
@@ -449,7 +449,7 @@ Model override note:
|
449 | 449 | } |
450 | 450 | ``` |
451 | 451 | |
452 | | -`maxConcurrentRuns` limits both scheduled cron dispatch and isolated agent-turn execution. Isolated cron agent turns use the queue's dedicated `cron-nested` execution lane internally, so raising this value lets independent cron LLM runs progress in parallel instead of only starting their outer cron wrappers. The shared non-cron `nested` lane is not widened by this setting. |
| 452 | +`maxConcurrentRuns` limits both scheduled cron dispatch and isolated agent-turn execution, and defaults to 8. Isolated cron agent turns use the queue's dedicated `cron-nested` execution lane internally, so raising this value lets independent cron LLM runs progress in parallel instead of only starting their outer cron wrappers. The shared non-cron `nested` lane is not widened by this setting. |
453 | 453 | |
454 | 454 | The runtime state sidecar is derived from `cron.store`: a `.json` store such as `~/clawd/cron/jobs.json` uses `~/clawd/cron/jobs-state.json`, while a store path without a `.json` suffix appends `-state.json`. |
455 | 455 | |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -385,7 +385,7 @@ Save to `~/.openclaw/openclaw.json` and you can DM the bot from that number.
|
385 | 385 | cron: { |
386 | 386 | enabled: true, |
387 | 387 | store: "~/.openclaw/cron/cron.json", |
388 | | - maxConcurrentRuns: 2, // cron dispatch + isolated cron agent-turn execution |
| 388 | + maxConcurrentRuns: 8, // default; cron dispatch + isolated cron agent-turn execution |
389 | 389 | sessionRetention: "24h", |
390 | 390 | runLog: { |
391 | 391 | maxBytes: "2mb", |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -1240,7 +1240,7 @@ Current builds no longer include the TCP bridge. Nodes connect over the Gateway
|
1240 | 1240 | { |
1241 | 1241 | cron: { |
1242 | 1242 | enabled: true, |
1243 | | - maxConcurrentRuns: 2, // cron dispatch + isolated cron agent-turn execution |
| 1243 | + maxConcurrentRuns: 8, // default; cron dispatch + isolated cron agent-turn execution |
1244 | 1244 | webhook: "https://example.invalid/legacy", // deprecated fallback for stored notify:true jobs |
1245 | 1245 | webhookToken: "replace-with-dedicated-token", // optional bearer token for outbound webhook auth |
1246 | 1246 | sessionRetention: "24h", // duration string or false |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -419,7 +419,7 @@ candidate contains redacted secret placeholders such as `***`.
|
419 | 419 | { |
420 | 420 | cron: { |
421 | 421 | enabled: true, |
422 | | - maxConcurrentRuns: 2, // cron dispatch + isolated cron agent-turn execution |
| 422 | + maxConcurrentRuns: 8, // default; cron dispatch + isolated cron agent-turn execution |
423 | 423 | sessionRetention: "24h", |
424 | 424 | runLog: { |
425 | 425 | maxBytes: "2mb", |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -6,13 +6,15 @@ import {
|
6 | 6 | resolveAgentMaxConcurrent, |
7 | 7 | resolveSubagentMaxConcurrent, |
8 | 8 | } from "./agent-limits.js"; |
| 9 | +import { DEFAULT_CRON_MAX_CONCURRENT_RUNS, resolveCronMaxConcurrentRuns } from "./cron-limits.js"; |
9 | 10 | import { applyAgentDefaults } from "./defaults.js"; |
10 | 11 | import { OpenClawSchema } from "./zod-schema.js"; |
11 | 12 | |
12 | 13 | describe("agent concurrency defaults", () => { |
13 | 14 | it("resolves defaults when unset", () => { |
14 | 15 | expect(resolveAgentMaxConcurrent({})).toBe(DEFAULT_AGENT_MAX_CONCURRENT); |
15 | 16 | expect(resolveSubagentMaxConcurrent({})).toBe(DEFAULT_SUBAGENT_MAX_CONCURRENT); |
| 17 | +expect(resolveCronMaxConcurrentRuns()).toBe(DEFAULT_CRON_MAX_CONCURRENT_RUNS); |
16 | 18 | }); |
17 | 19 | |
18 | 20 | it("clamps invalid values to at least 1", () => { |
@@ -26,6 +28,7 @@ describe("agent concurrency defaults", () => {
|
26 | 28 | }; |
27 | 29 | expect(resolveAgentMaxConcurrent(cfg)).toBe(1); |
28 | 30 | expect(resolveSubagentMaxConcurrent(cfg)).toBe(1); |
| 31 | +expect(resolveCronMaxConcurrentRuns({ maxConcurrentRuns: 0 })).toBe(1); |
29 | 32 | }); |
30 | 33 | |
31 | 34 | it("accepts subagent spawn depth and per-agent child limits", () => { |
|
| Original file line number | Diff line number | Diff line change |
|---|
|
| 1 | +import type { CronConfig } from "./types.cron.js"; |
| 2 | + |
| 3 | +export const DEFAULT_CRON_MAX_CONCURRENT_RUNS = 8; |
| 4 | + |
| 5 | +export function resolveCronMaxConcurrentRuns( |
| 6 | +cronConfig?: Pick<CronConfig, "maxConcurrentRuns">, |
| 7 | +): number { |
| 8 | +const raw = cronConfig?.maxConcurrentRuns; |
| 9 | +if (typeof raw === "number" && Number.isFinite(raw)) { |
| 10 | +return Math.max(1, Math.floor(raw)); |
| 11 | +} |
| 12 | +return DEFAULT_CRON_MAX_CONCURRENT_RUNS; |
| 13 | +} |
| Original file line number | Diff line number | Diff line change |
|---|
@@ -4,9 +4,11 @@ import {
|
4 | 4 | DEFAULT_SUBAGENT_ARCHIVE_AFTER_MINUTES, |
5 | 5 | DEFAULT_SUBAGENT_MAX_CONCURRENT, |
6 | 6 | } from "./agent-limits.js"; |
| 7 | +import { DEFAULT_CRON_MAX_CONCURRENT_RUNS } from "./cron-limits.js"; |
7 | 8 | import { |
8 | 9 | applyAgentDefaults, |
9 | 10 | applyContextPruningDefaults, |
| 11 | +applyCronDefaults, |
10 | 12 | applyMessageDefaults, |
11 | 13 | } from "./defaults.js"; |
12 | 14 | |
@@ -121,6 +123,18 @@ describe("config defaults", () => {
|
121 | 123 | ); |
122 | 124 | }); |
123 | 125 | |
| 126 | +it("fills missing cron concurrency default", () => { |
| 127 | +const next = applyCronDefaults({ messages: {} } as never); |
| 128 | + |
| 129 | +expect(next.cron?.maxConcurrentRuns).toBe(DEFAULT_CRON_MAX_CONCURRENT_RUNS); |
| 130 | +}); |
| 131 | + |
| 132 | +it("preserves explicit cron concurrency", () => { |
| 133 | +const next = applyCronDefaults({ cron: { maxConcurrentRuns: 3 } } as never); |
| 134 | + |
| 135 | +expect(next.cron?.maxConcurrentRuns).toBe(3); |
| 136 | +}); |
| 137 | + |
124 | 138 | it("preserves explicit subagent archive default", () => { |
125 | 139 | const next = applyAgentDefaults({ |
126 | 140 | agents: { defaults: { subagents: { archiveAfterMinutes: 0 } } }, |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -7,6 +7,7 @@ import {
|
7 | 7 | DEFAULT_SUBAGENT_ARCHIVE_AFTER_MINUTES, |
8 | 8 | DEFAULT_SUBAGENT_MAX_CONCURRENT, |
9 | 9 | } from "./agent-limits.js"; |
| 10 | +import { DEFAULT_CRON_MAX_CONCURRENT_RUNS } from "./cron-limits.js"; |
10 | 11 | import { normalizeAgentModelMapForConfig, normalizeAgentModelRefForConfig } from "./model-input.js"; |
11 | 12 | import { |
12 | 13 | applyProviderConfigDefaultsForConfig, |
@@ -438,6 +439,20 @@ export function applyAgentDefaults(cfg: OpenClawConfig): OpenClawConfig {
|
438 | 439 | }; |
439 | 440 | } |
440 | 441 | |
| 442 | +export function applyCronDefaults(cfg: OpenClawConfig): OpenClawConfig { |
| 443 | +const raw = cfg.cron?.maxConcurrentRuns; |
| 444 | +if (typeof raw === "number" && Number.isFinite(raw)) { |
| 445 | +return cfg; |
| 446 | +} |
| 447 | +return { |
| 448 | + ...cfg, |
| 449 | +cron: { |
| 450 | + ...cfg.cron, |
| 451 | +maxConcurrentRuns: DEFAULT_CRON_MAX_CONCURRENT_RUNS, |
| 452 | +}, |
| 453 | +}; |
| 454 | +} |
| 455 | + |
441 | 456 | export function applyLoggingDefaults(cfg: OpenClawConfig): OpenClawConfig { |
442 | 457 | const logging = cfg.logging; |
443 | 458 | if (!logging) { |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -3,6 +3,7 @@ import {
|
3 | 3 | applyCompactionDefaults, |
4 | 4 | applyContextPruningDefaults, |
5 | 5 | applyAgentDefaults, |
| 6 | +applyCronDefaults, |
6 | 7 | applyLoggingDefaults, |
7 | 8 | applyMessageDefaults, |
8 | 9 | applyModelDefaults, |
@@ -63,6 +64,7 @@ export function materializeRuntimeConfig(
|
63 | 64 | } |
64 | 65 | next = applySessionDefaults(next); |
65 | 66 | next = applyAgentDefaults(next); |
| 67 | +next = applyCronDefaults(next); |
66 | 68 | if (profile.includeContextPruningDefaults) { |
67 | 69 | next = applyContextPruningDefaults(next, { manifestRegistry: options.manifestRegistry }); |
68 | 70 | } |
|
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。