fix(memory): bound qmd embed backoff

This commit is contained in:
Peter Steinberger
2026-05-30 14:39:33 -04:00
parent 6399b6a445
commit caac9733a7
2 changed files with 41 additions and 3 deletions

View File

@@ -3822,6 +3822,40 @@ describe("QmdMemoryManager", () => {
await manager.close();
});
it("does not store qmd embed backoff when the process clock is invalid", async () => {
cfg = {
...cfg,
memory: {
backend: "qmd",
qmd: {
includeDefaultMemory: false,
searchMode: "query",
update: {
interval: "0s",
debounceMs: 0,
onBoot: false,
},
paths: [{ path: workspaceDir, pattern: "**/*.md", name: "workspace" }],
},
},
} as OpenClawConfig;
const dateNowSpy = vi.spyOn(Date, "now").mockReturnValue(8_640_000_000_000_001);
const { manager } = await createManager({ mode: "status" });
try {
(
manager as unknown as {
noteEmbedFailure: (reason: string, err: unknown) => void;
}
).noteEmbedFailure("manual", new Error("embed failed"));
} finally {
dateNowSpy.mockRestore();
}
const status = manager.status() as { custom?: { qmd?: { embedBackoffUntil?: number | null } } };
expect(status.custom?.qmd?.embedBackoffUntil).toBeNull();
await manager.close();
});
it("runs periodic embed maintenance even when regular update scheduling is disabled", async () => {
vi.useFakeTimers();
cfg = {

View File

@@ -49,7 +49,11 @@ import {
type ResolvedQmdConfig,
type ResolvedQmdMcporterConfig,
} from "openclaw/plugin-sdk/memory-core-host-engine-storage";
import { addTimerTimeoutGraceMs } from "openclaw/plugin-sdk/number-runtime";
import {
addTimerTimeoutGraceMs,
isFutureDateTimestampMs,
resolveExpiresAtMsFromDurationMs,
} from "openclaw/plugin-sdk/number-runtime";
import {
localeLowercasePreservingWhitespace,
normalizeLowercaseStringOrEmpty,
@@ -1701,7 +1705,7 @@ export class QmdMemoryManager implements MemorySearchManager {
return false;
}
const now = Date.now();
if (this.embedBackoffUntil !== null && now < this.embedBackoffUntil) {
if (this.embedBackoffUntil !== null && isFutureDateTimestampMs(this.embedBackoffUntil)) {
return false;
}
const embedIntervalMs = this.qmd.update.embedIntervalMs;
@@ -1808,7 +1812,7 @@ export class QmdMemoryManager implements MemorySearchManager {
QMD_EMBED_BACKOFF_MAX_MS,
QMD_EMBED_BACKOFF_BASE_MS * 2 ** Math.max(0, this.embedFailureCount - 1),
);
this.embedBackoffUntil = Date.now() + delayMs;
this.embedBackoffUntil = resolveExpiresAtMsFromDurationMs(delayMs) ?? null;
log.warn(
`qmd embed failed (${reason}): ${String(err)}; backing off for ${Math.ceil(delayMs / 1000)}s`,
);