mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-07 22:09:57 +00:00
* feat: detect stale Slack sockets and auto-restart
Slack Socket Mode connections can silently stop delivering events while
still appearing connected (health checks pass, WebSocket stays open).
This "half-dead socket" problem causes messages to go unanswered.
This commit adds two layers of protection:
1. **Event liveness tracking**: Every inbound Slack event (messages,
reactions, member joins/leaves, channel events, pins) now calls
`setStatus({ lastEventAt, lastInboundAt })` to update the channel
account snapshot with the timestamp of the last received event.
2. **Health monitor stale socket detection**: The channel health monitor
now checks `lastEventAt` against a configurable threshold (default
30 minutes). If a channel has been running longer than the threshold
and hasn't received any events in that window, it is flagged as
unhealthy and automatically restarted — the same way disconnected
or crashed channels are already handled.
The restart reason is logged as "stale-socket" for observability, and
the existing cooldown/rate-limit logic (3 restarts/hour max) prevents
restart storms.
* Slack: gate liveness tracking to accepted events
---------
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
28 lines
1.3 KiB
TypeScript
28 lines
1.3 KiB
TypeScript
import type { ResolvedSlackAccount } from "../accounts.js";
|
|
import type { SlackMonitorContext } from "./context.js";
|
|
import { registerSlackChannelEvents } from "./events/channels.js";
|
|
import { registerSlackInteractionEvents } from "./events/interactions.js";
|
|
import { registerSlackMemberEvents } from "./events/members.js";
|
|
import { registerSlackMessageEvents } from "./events/messages.js";
|
|
import { registerSlackPinEvents } from "./events/pins.js";
|
|
import { registerSlackReactionEvents } from "./events/reactions.js";
|
|
import type { SlackMessageHandler } from "./message-handler.js";
|
|
|
|
export function registerSlackMonitorEvents(params: {
|
|
ctx: SlackMonitorContext;
|
|
account: ResolvedSlackAccount;
|
|
handleSlackMessage: SlackMessageHandler;
|
|
/** Called on each inbound event to update liveness tracking. */
|
|
trackEvent?: () => void;
|
|
}) {
|
|
registerSlackMessageEvents({
|
|
ctx: params.ctx,
|
|
handleSlackMessage: params.handleSlackMessage,
|
|
});
|
|
registerSlackReactionEvents({ ctx: params.ctx, trackEvent: params.trackEvent });
|
|
registerSlackMemberEvents({ ctx: params.ctx, trackEvent: params.trackEvent });
|
|
registerSlackChannelEvents({ ctx: params.ctx, trackEvent: params.trackEvent });
|
|
registerSlackPinEvents({ ctx: params.ctx, trackEvent: params.trackEvent });
|
|
registerSlackInteractionEvents({ ctx: params.ctx });
|
|
}
|