mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-28 06:21:19 +00:00
fix(plugins): remove abort listener when channel runtime context is disposed (#109708)
This commit is contained in:
committed by
GitHub
parent
62db322715
commit
bd7b0ad85f
@@ -115,6 +115,9 @@ export function createChannelRuntimeContextRegistry(): ChannelRuntimeContextRegi
|
||||
return;
|
||||
}
|
||||
disposed = true;
|
||||
// Detach before the token check: stale leases disposed after a replacement
|
||||
// registered must still release their listener on long-lived signals.
|
||||
params.abortSignal?.removeEventListener("abort", dispose);
|
||||
const current = runtimeContexts.get(normalized.mapKey);
|
||||
if (!current || current.token !== token) {
|
||||
return;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// Runtime channel tests cover channel plugin runtime send, reply, and capability behavior.
|
||||
import { getEventListeners } from "node:events";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { createRuntimeChannel } from "./runtime-channel.js";
|
||||
|
||||
@@ -89,6 +90,60 @@ describe("runtimeContexts", () => {
|
||||
lease.dispose();
|
||||
});
|
||||
|
||||
it("removes its abort listener when the lease is disposed", () => {
|
||||
const channel = createRuntimeChannel();
|
||||
const controller = new AbortController();
|
||||
const initialListenerCount = getEventListeners(controller.signal, "abort").length;
|
||||
const lease = channel.runtimeContexts.register({
|
||||
channelId: "telegram",
|
||||
accountId: "default",
|
||||
capability: "approval.native",
|
||||
context: { token: "abc" },
|
||||
abortSignal: controller.signal,
|
||||
});
|
||||
|
||||
expect(getEventListeners(controller.signal, "abort")).toHaveLength(initialListenerCount + 1);
|
||||
|
||||
lease.dispose();
|
||||
|
||||
expect(getEventListeners(controller.signal, "abort")).toHaveLength(initialListenerCount);
|
||||
});
|
||||
|
||||
it("removes the stale lease abort listener after a replacement registration", () => {
|
||||
const channel = createRuntimeChannel();
|
||||
const controller = new AbortController();
|
||||
const initialListenerCount = getEventListeners(controller.signal, "abort").length;
|
||||
const staleLease = channel.runtimeContexts.register({
|
||||
channelId: "whatsapp",
|
||||
accountId: "default",
|
||||
capability: "connection.controller",
|
||||
context: { token: "stale" },
|
||||
abortSignal: controller.signal,
|
||||
});
|
||||
channel.runtimeContexts.register({
|
||||
channelId: "whatsapp",
|
||||
accountId: "default",
|
||||
capability: "connection.controller",
|
||||
context: { token: "replacement" },
|
||||
abortSignal: controller.signal,
|
||||
});
|
||||
|
||||
expect(getEventListeners(controller.signal, "abort")).toHaveLength(initialListenerCount + 2);
|
||||
|
||||
// Channel plugins dispose the previous lease after registering its replacement,
|
||||
// so the stale token check must not skip listener cleanup.
|
||||
staleLease.dispose();
|
||||
|
||||
expect(getEventListeners(controller.signal, "abort")).toHaveLength(initialListenerCount + 1);
|
||||
expect(
|
||||
channel.runtimeContexts.get({
|
||||
channelId: "whatsapp",
|
||||
accountId: "default",
|
||||
capability: "connection.controller",
|
||||
}),
|
||||
).toEqual({ token: "replacement" });
|
||||
});
|
||||
|
||||
it("does not register contexts when the abort signal is already aborted", () => {
|
||||
const channel = createRuntimeChannel();
|
||||
const onEvent = vi.fn();
|
||||
|
||||
Reference in New Issue
Block a user