fix(synology-chat): deregister stale webhook route before re-registering on restart (#24971)

When the Synology Chat plugin restarts (auto-restart or health monitor),
startAccount is called again without calling the previous stop(). The
HTTP route is still registered, so registerPluginHttpRoute returns a
no-op unregister function and logs "already registered". This triggers
another restart, creating an infinite loop.

Store the unregister function at module level keyed by account+path.
Before registering, check for and call any stale unregister from the
previous start cycle, ensuring a clean slate for route registration.

Fixes #24894

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Sid
2026-02-24 11:33:47 +08:00
committed by GitHub
parent 9ced64054f
commit f5cab29ec7

View File

@@ -20,6 +20,8 @@ import { createWebhookHandler } from "./webhook-handler.js";
const CHANNEL_ID = "synology-chat"; const CHANNEL_ID = "synology-chat";
const SynologyChatConfigSchema = buildChannelConfigSchema(z.object({}).passthrough()); const SynologyChatConfigSchema = buildChannelConfigSchema(z.object({}).passthrough());
const activeRouteUnregisters = new Map<string, () => void>();
export function createSynologyChatPlugin() { export function createSynologyChatPlugin() {
return { return {
id: CHANNEL_ID, id: CHANNEL_ID,
@@ -270,7 +272,16 @@ export function createSynologyChatPlugin() {
log, log,
}); });
// Register HTTP route via the SDK // Deregister any stale route from a previous start (e.g. on auto-restart)
// to avoid "already registered" collisions that trigger infinite loops.
const routeKey = `${accountId}:${account.webhookPath}`;
const prevUnregister = activeRouteUnregisters.get(routeKey);
if (prevUnregister) {
log?.info?.(`Deregistering stale route before re-registering: ${account.webhookPath}`);
prevUnregister();
activeRouteUnregisters.delete(routeKey);
}
const unregister = registerPluginHttpRoute({ const unregister = registerPluginHttpRoute({
path: account.webhookPath, path: account.webhookPath,
pluginId: CHANNEL_ID, pluginId: CHANNEL_ID,
@@ -278,6 +289,7 @@ export function createSynologyChatPlugin() {
log: (msg: string) => log?.info?.(msg), log: (msg: string) => log?.info?.(msg),
handler, handler,
}); });
activeRouteUnregisters.set(routeKey, unregister);
log?.info?.(`Registered HTTP route: ${account.webhookPath} for Synology Chat`); log?.info?.(`Registered HTTP route: ${account.webhookPath} for Synology Chat`);
@@ -285,6 +297,7 @@ export function createSynologyChatPlugin() {
stop: () => { stop: () => {
log?.info?.(`Stopping Synology Chat channel (account: ${accountId})`); log?.info?.(`Stopping Synology Chat channel (account: ${accountId})`);
if (typeof unregister === "function") unregister(); if (typeof unregister === "function") unregister();
activeRouteUnregisters.delete(routeKey);
}, },
}; };
}, },