mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-12 07:20:45 +00:00
fix: harden msteams monitor lifecycle edges (#24580) (thanks @chilu18)
This commit is contained in:
@@ -47,6 +47,7 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
### Fixes
|
||||
|
||||
- MSTeams/gateway lifecycle: keep `startAccount` pending until shutdown/abort to stop false auto-restart loops, fail fast on startup bind errors, and add lifecycle regressions for abort + startup failure behavior. (#24580) Thanks @chilu18.
|
||||
- Synology Chat/webhook compatibility: accept JSON and alias payload fields, allow token resolution from body/query/header sources, and ACK webhook requests with `204` to avoid persistent `Processing...` states in Synology Chat clients. (#26635) Thanks @memphislee09-source.
|
||||
- Synology Chat/webhook ingress hardening: enforce bounded body reads (size + timeout) via shared request-body guards to prevent unauthenticated slow-body hangs before token validation. (#25831) Thanks @bmendonca3.
|
||||
- Synology Chat/reply delivery: resolve webhook usernames to Chat API `user_id` values for outbound chatbot replies, avoiding mismatches between webhook user IDs and `method=chatbot` recipient IDs in multi-account setups. (#23709) Thanks @druide67.
|
||||
|
||||
@@ -175,6 +175,24 @@ describe("monitorMSTeamsProvider lifecycle", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("returns a shutdown handle when abort signal is not provided", async () => {
|
||||
const stores = createStores();
|
||||
const result = await monitorMSTeamsProvider({
|
||||
cfg: createConfig(0),
|
||||
runtime: createRuntime(),
|
||||
conversationStore: stores.conversationStore,
|
||||
pollStore: stores.pollStore,
|
||||
});
|
||||
|
||||
expect(result).toEqual(
|
||||
expect.objectContaining({
|
||||
shutdown: expect.any(Function),
|
||||
}),
|
||||
);
|
||||
|
||||
await expect(result.shutdown()).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it("rejects startup when webhook port is already in use", async () => {
|
||||
expressControl.mode.value = "error";
|
||||
await expect(
|
||||
|
||||
@@ -277,7 +277,6 @@ export async function monitorMSTeamsProvider(
|
||||
const httpServer = expressApp.listen(port);
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const onListening = () => {
|
||||
httpServer.off("error", onError);
|
||||
log.info(`msteams provider started on port ${port}`);
|
||||
resolve();
|
||||
};
|
||||
@@ -306,24 +305,30 @@ export async function monitorMSTeamsProvider(
|
||||
});
|
||||
};
|
||||
|
||||
// Handle abort signal
|
||||
const onAbort = () => {
|
||||
void shutdown();
|
||||
};
|
||||
if (opts.abortSignal) {
|
||||
if (opts.abortSignal.aborted) {
|
||||
onAbort();
|
||||
} else {
|
||||
opts.abortSignal.addEventListener("abort", onAbort, { once: true });
|
||||
}
|
||||
// Some direct callers may invoke monitor without lifecycle wiring.
|
||||
// Return immediately so they can call shutdown explicitly.
|
||||
if (!opts.abortSignal) {
|
||||
return { app: expressApp, shutdown };
|
||||
}
|
||||
|
||||
// Keep this task alive until shutdown/close so gateway runtime does not treat startup as exit.
|
||||
await new Promise<void>((resolve) => {
|
||||
const closePromise = new Promise<void>((resolve) => {
|
||||
httpServer.once("close", () => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
// Handle abort signal
|
||||
const onAbort = () => {
|
||||
void shutdown();
|
||||
};
|
||||
if (opts.abortSignal.aborted) {
|
||||
onAbort();
|
||||
} else {
|
||||
opts.abortSignal.addEventListener("abort", onAbort, { once: true });
|
||||
}
|
||||
|
||||
// Keep this task alive until shutdown/close so gateway runtime does not treat startup as exit.
|
||||
await closePromise;
|
||||
opts.abortSignal?.removeEventListener("abort", onAbort);
|
||||
|
||||
return { app: expressApp, shutdown };
|
||||
|
||||
Reference in New Issue
Block a user