fix: clear session suspension timers on gateway shutdown

This commit is contained in:
clawsweeper 2026-07-09 13:36:09 +00:00
parent 8fc35fb2cd
commit c5aeee1d5c
2 changed files with 14 additions and 19 deletions

View file

@ -1,7 +1,6 @@
// Verifies quota suspension persists lane state and auto-resumes safely.
import { afterEach, describe, expect, it, vi } from "vitest";
import { DEFAULT_CRON_MAX_CONCURRENT_RUNS } from "../config/cron-limits.js";
import type { QuotaSuspension } from "../config/sessions/types.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { CommandLane } from "../process/lanes.js";
import { MAX_TIMER_TIMEOUT_MS } from "../shared/number-coercion.js";
@ -135,10 +134,8 @@ describe("session suspension", () => {
await suspendLane(Number.MAX_SAFE_INTEGER, {} as OpenClawConfig, CommandLane.Main);
expect(setTimeoutSpy).toHaveBeenCalledWith(expect.any(Function), MAX_TIMER_TIMEOUT_MS);
const patch = sessionStoreMocks.applySessionStoreEntryPatch.mock.calls[0]?.[0].patch as {
quotaSuspension?: QuotaSuspension;
};
const expectedSuspension: QuotaSuspension = {
const patch = sessionStoreMocks.applySessionStoreEntryPatch.mock.calls[0]?.[0].patch;
const expectedSuspension = {
schemaVersion: 1,
suspendedAt: 1_000,
reason: "quota_exhausted",
@ -147,7 +144,7 @@ describe("session suspension", () => {
laneId: CommandLane.Main,
expectedResumeBy: 1_000 + MAX_TIMER_TIMEOUT_MS,
state: "suspended",
};
} as const;
expect(patch.quotaSuspension).toMatchObject(expectedSuspension);
expect(patch.quotaSuspension).toStrictEqual({
...expectedSuspension,

View file

@ -8,7 +8,6 @@ import path from "node:path";
import { resolveAgentMaxConcurrent, resolveSubagentMaxConcurrent } from "../config/agent-limits.js";
import { resolveCronMaxConcurrentRuns } from "../config/cron-limits.js";
import { applySessionStoreEntryPatch } from "../config/sessions.js";
import type { QuotaSuspension } from "../config/sessions/types.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { createSubsystemLogger } from "../logging/subsystem.js";
import { setCommandLaneConcurrency } from "../process/command-queue.js";
@ -133,17 +132,6 @@ export async function suspendSession(params: SessionSuspensionParams) {
const ttlMs = resolveTimerTimeoutMs(params.ttlMs, DEFAULT_QUOTA_SUSPENSION_RESUME_MS, 0);
const now = Date.now();
const expectedResumeBy = resolveExpiresAtMsFromDurationMs(ttlMs, { nowMs: now }) ?? now;
const quotaSuspension: QuotaSuspension = {
schemaVersion: 1,
suspendedAt: now,
reason: params.reason,
failedProvider: params.failedProvider,
failedModel: params.failedModel,
summary: params.summary,
laneId: params.laneId,
expectedResumeBy,
state: "suspended",
};
try {
await applySessionStoreEntryPatch({
@ -152,7 +140,17 @@ export async function suspendSession(params: SessionSuspensionParams) {
skipMaintenance: true,
takeCacheOwnership: true,
patch: {
quotaSuspension,
quotaSuspension: {
schemaVersion: 1,
suspendedAt: now,
reason: params.reason,
failedProvider: params.failedProvider,
failedModel: params.failedModel,
summary: params.summary,
laneId: params.laneId,
expectedResumeBy,
state: "suspended",
},
},
});
} catch (err) {