fix(memory-core): retry disabled dreaming cron cleanup

This commit is contained in:
Neerav Makwana
2026-05-15 21:51:02 -04:00
committed by Peter Steinberger
parent 440333125c
commit ccdcdc7d1b
2 changed files with 72 additions and 23 deletions

View File

@@ -1535,7 +1535,70 @@ describe("gateway startup reconciliation", () => {
}
});
it("does not reschedule startup cron retry from stale enabled config after runtime config disables dreaming", async () => {
it("retries disabled startup cleanup until cron is available", async () => {
vi.useFakeTimers();
clearInternalHooks();
const logger = createLogger();
const managedJob: CronJobLike = {
id: "job-managed",
name: constants.MANAGED_DREAMING_CRON_NAME,
description: `${constants.MANAGED_DREAMING_CRON_TAG} test`,
enabled: true,
schedule: { kind: "cron", expr: "0 3 * * *" },
sessionTarget: "main",
wakeMode: "now",
payload: { kind: "systemEvent", text: constants.DREAMING_SYSTEM_EVENT_TEXT },
createdAtMs: 10,
};
const harness = createCronHarness([managedJob]);
const onMock = vi.fn();
const api: DreamingPluginApiTestDouble = {
config: {
plugins: {
entries: {
"memory-core": {
config: {
dreaming: {
enabled: false,
frequency: "15 4 * * *",
timezone: "UTC",
},
},
},
},
},
},
pluginConfig: {},
logger,
runtime: {},
on: onMock,
};
try {
registerShortTermPromotionDreamingForTest(api);
let cronAvailable = false;
await triggerGatewayStart(onMock, {
config: api.config,
getCron: () => (cronAvailable ? harness.cron : undefined),
});
await vi.advanceTimersByTimeAsync(constants.STARTUP_CRON_RETRY_DELAY_MS);
expect(harness.removeCalls).toHaveLength(0);
cronAvailable = true;
await vi.advanceTimersByTimeAsync(constants.STARTUP_CRON_RETRY_DELAY_MS);
expect(harness.removeCalls).toEqual(["job-managed"]);
expect(harness.jobs).toHaveLength(0);
expect(harness.addCalls).toHaveLength(0);
expectLogContains(logger.info, "removed 1 managed dreaming cron job");
} finally {
vi.useRealTimers();
clearInternalHooks();
}
});
it("does not recreate startup cron from stale enabled config after runtime config disables dreaming", async () => {
vi.useFakeTimers();
clearInternalHooks();
const logger = createLogger();

View File

@@ -694,14 +694,6 @@ export function registerShortTermPromotionDreaming(api: OpenClawPluginApi): void
const resolveCurrentConfig = (): OpenClawConfig =>
(api.runtime.config?.current?.() ?? api.config) as OpenClawConfig;
const resolveCurrentDreamingConfig = (): ShortTermPromotionDreamingConfig => {
const cfg = resolveCurrentConfig();
return resolveShortTermPromotionDreamingConfig({
pluginConfig: resolveMemoryCorePluginConfig(cfg),
cfg,
});
};
const clearStartupCronRetry = (): void => {
if (startupCronRetryTimer) {
clearTimeout(startupCronRetryTimer);
@@ -823,8 +815,8 @@ export function registerShortTermPromotionDreaming(api: OpenClawPluginApi): void
return config;
};
const scheduleStartupCronRetry = (config: ShortTermPromotionDreamingConfig): void => {
if (disposed || !config.enabled || hasStartupCron()) {
const scheduleStartupCronRetry = (): void => {
if (disposed || hasStartupCron()) {
clearStartupCronRetry();
return;
}
@@ -838,12 +830,12 @@ export function registerShortTermPromotionDreaming(api: OpenClawPluginApi): void
}
startupCronRetryAttempts += 1;
void reconcileManagedDreamingCron({ reason: "runtime" })
.then((latestConfig) => {
if (disposed || !latestConfig.enabled || hasStartupCron()) {
.then(() => {
if (disposed || hasStartupCron()) {
clearStartupCronRetry();
return;
}
scheduleStartupCronRetry(latestConfig);
scheduleStartupCronRetry();
})
.catch((err) => {
if (disposed) {
@@ -852,13 +844,7 @@ export function registerShortTermPromotionDreaming(api: OpenClawPluginApi): void
api.logger.error(
`memory-core: deferred dreaming cron retry failed: ${formatErrorMessage(err)}`,
);
try {
scheduleStartupCronRetry(resolveCurrentDreamingConfig());
} catch (configErr) {
api.logger.error(
`memory-core: deferred dreaming cron retry config refresh failed: ${formatErrorMessage(configErr)}`,
);
}
scheduleStartupCronRetry();
});
}, STARTUP_CRON_RETRY_DELAY_MS);
};
@@ -868,12 +854,12 @@ export function registerShortTermPromotionDreaming(api: OpenClawPluginApi): void
// Store the gateway context for runtime cron resolution retries.
gatewayContext = ctx as unknown as { getCron?: () => CronServiceLike | null };
try {
const config = await reconcileManagedDreamingCron({
await reconcileManagedDreamingCron({
reason: "startup",
startupConfig: ctx.config,
startupCron: () => resolveCronServiceFromGatewayContext(ctx),
});
scheduleStartupCronRetry(config);
scheduleStartupCronRetry();
} catch (err) {
api.logger.error(
`memory-core: dreaming startup reconciliation failed: ${formatErrorMessage(err)}`,