mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 10:50:44 +00:00
fix: keep cleanup alive across registry refresh
This commit is contained in:
@@ -68,6 +68,15 @@ function expectRouteRegistryState(params: { setup: () => void; assert: () => voi
|
||||
params.assert();
|
||||
}
|
||||
|
||||
async function waitForCleanupSignal(signal: Promise<void>, label: string): Promise<void> {
|
||||
await Promise.race([
|
||||
signal,
|
||||
new Promise<never>((_, reject) => {
|
||||
setTimeout(() => reject(new Error(`Timed out waiting for ${label}`)), 500);
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
||||
describe("plugin runtime route registry", () => {
|
||||
afterEach(() => {
|
||||
releasePinnedPluginHttpRouteRegistry();
|
||||
@@ -209,6 +218,65 @@ describe("setActivePluginRegistry", () => {
|
||||
expect(listImportedRuntimePluginIds()).toEqual(["runtime-plugin"]);
|
||||
});
|
||||
|
||||
it("continues cleanup when the same active registry is refreshed", async () => {
|
||||
let releaseFirstCleanup: (() => void) | undefined;
|
||||
let markFirstCleanupStarted!: () => void;
|
||||
let markSecondCleanupCalled!: () => void;
|
||||
const firstCleanupStarted = new Promise<void>((resolve) => {
|
||||
markFirstCleanupStarted = resolve;
|
||||
});
|
||||
const secondCleanupCalled = new Promise<void>((resolve) => {
|
||||
markSecondCleanupCalled = resolve;
|
||||
});
|
||||
const previous = createEmptyPluginRegistry();
|
||||
previous.plugins.push(
|
||||
createPluginRecord({
|
||||
id: "cleanup-refresh-race",
|
||||
name: "Cleanup Refresh Race",
|
||||
status: "loaded",
|
||||
}),
|
||||
);
|
||||
previous.runtimeLifecycles = [
|
||||
{
|
||||
pluginId: "cleanup-refresh-race",
|
||||
pluginName: "Cleanup Refresh Race",
|
||||
lifecycle: {
|
||||
id: "first-cleanup",
|
||||
async cleanup() {
|
||||
markFirstCleanupStarted();
|
||||
await new Promise<void>((resolve) => {
|
||||
releaseFirstCleanup = resolve;
|
||||
});
|
||||
},
|
||||
},
|
||||
source: "/virtual/cleanup-refresh-race/index.ts",
|
||||
rootDir: "/virtual/cleanup-refresh-race",
|
||||
},
|
||||
{
|
||||
pluginId: "cleanup-refresh-race",
|
||||
pluginName: "Cleanup Refresh Race",
|
||||
lifecycle: {
|
||||
id: "second-cleanup",
|
||||
cleanup() {
|
||||
markSecondCleanupCalled();
|
||||
},
|
||||
},
|
||||
source: "/virtual/cleanup-refresh-race/index.ts",
|
||||
rootDir: "/virtual/cleanup-refresh-race",
|
||||
},
|
||||
];
|
||||
const next = createEmptyPluginRegistry();
|
||||
|
||||
setActivePluginRegistry(previous);
|
||||
setActivePluginRegistry(next);
|
||||
await waitForCleanupSignal(firstCleanupStarted, "first cleanup start");
|
||||
|
||||
setActivePluginRegistry(next);
|
||||
releaseFirstCleanup?.();
|
||||
|
||||
await waitForCleanupSignal(secondCleanupCalled, "second cleanup");
|
||||
});
|
||||
|
||||
it("includes plugin ids imported before registration failed", () => {
|
||||
recordImportedPluginId("broken-plugin");
|
||||
|
||||
|
||||
@@ -74,10 +74,10 @@ async function cleanupPreviousPluginHostRegistry(params: {
|
||||
if (!nextRegistry || nextRegistry === params.previousRegistry) {
|
||||
return;
|
||||
}
|
||||
const cleanupActiveVersion = state.activeVersion;
|
||||
// Async cleanup must not clear state after another registry becomes live.
|
||||
const shouldCleanup = () =>
|
||||
state.activeVersion === cleanupActiveVersion && state.activeRegistry === nextRegistry;
|
||||
// Re-activating the same registry refreshes caches, but it is still the same
|
||||
// live cleanup target and must not abort the old registry cleanup.
|
||||
const shouldCleanup = () => state.activeRegistry === nextRegistry;
|
||||
await cleanupReplacedPluginHostRegistry({
|
||||
cfg: getRuntimeConfig(),
|
||||
previousRegistry: params.previousRegistry,
|
||||
|
||||
Reference in New Issue
Block a user