


























@@ -1,4 +1,5 @@
11import { afterEach, describe, expect, it, vi } from "vitest";
2+import { DEFAULT_CRON_MAX_CONCURRENT_RUNS } from "../config/cron-limits.js";
23import type { OpenClawConfig } from "../config/types.openclaw.js";
34import { CommandLane } from "../process/lanes.js";
45@@ -23,12 +24,12 @@ vi.mock("./command/session.js", () => ({
2324}),
2425}));
252626-async function suspendMainLane(ttlMs: number, cfg: OpenClawConfig) {
27+async function suspendLane(ttlMs: number, cfg: OpenClawConfig, laneId: CommandLane) {
2728const { suspendSession } = await import("./session-suspension.js");
2829await suspendSession({
2930 cfg,
3031sessionId: "session-1",
31-laneId: CommandLane.Main,
32+ laneId,
3233reason: "quota_exhausted",
3334failedProvider: "anthropic",
3435failedModel: "claude-opus-4-6",
@@ -40,6 +41,8 @@ describe("session suspension", () => {
4041afterEach(async () => {
4142const { cancelLaneAutoResume } = await import("./session-suspension.js");
4243cancelLaneAutoResume(CommandLane.Main);
44+cancelLaneAutoResume(CommandLane.Cron);
45+cancelLaneAutoResume(CommandLane.CronNested);
4346vi.useRealTimers();
4447sessionStoreMocks.updateSessionStoreEntry.mockClear();
4548commandQueueMocks.setCommandLaneConcurrency.mockClear();
@@ -51,7 +54,7 @@ describe("session suspension", () => {
5154agents: { defaults: { maxConcurrent: 4 } },
5255} as OpenClawConfig;
535654-await suspendMainLane(100, cfg);
57+await suspendLane(100, cfg, CommandLane.Main);
55585659expect(commandQueueMocks.setCommandLaneConcurrency).toHaveBeenCalledWith(CommandLane.Main, 0);
5760@@ -63,6 +66,44 @@ describe("session suspension", () => {
6366);
6467});
656869+it("auto-resumes cron lanes to the cron concurrency default", async () => {
70+vi.useFakeTimers();
71+72+await suspendLane(100, {} as OpenClawConfig, CommandLane.CronNested);
73+74+expect(commandQueueMocks.setCommandLaneConcurrency).toHaveBeenCalledWith(
75+CommandLane.CronNested,
76+0,
77+);
78+79+await vi.advanceTimersByTimeAsync(100);
80+81+expect(commandQueueMocks.setCommandLaneConcurrency).toHaveBeenLastCalledWith(
82+CommandLane.CronNested,
83+DEFAULT_CRON_MAX_CONCURRENT_RUNS,
84+);
85+});
86+87+it("auto-resumes cron lanes to configured and clamped cron concurrency", async () => {
88+vi.useFakeTimers();
89+90+await suspendLane(100, { cron: { maxConcurrentRuns: 3 } } as OpenClawConfig, CommandLane.Cron);
91+await vi.advanceTimersByTimeAsync(100);
92+93+expect(commandQueueMocks.setCommandLaneConcurrency).toHaveBeenLastCalledWith(
94+CommandLane.Cron,
95+3,
96+);
97+98+await suspendLane(100, { cron: { maxConcurrentRuns: 0 } } as OpenClawConfig, CommandLane.Cron);
99+await vi.advanceTimersByTimeAsync(100);
100+101+expect(commandQueueMocks.setCommandLaneConcurrency).toHaveBeenLastCalledWith(
102+CommandLane.Cron,
103+1,
104+);
105+});
106+66107it("maps failover reasons to persisted suspension reasons", async () => {
67108const { testing } = await import("./session-suspension.js");
68109此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。