fix: clarify slack socket retry errors

This commit is contained in:
Peter Steinberger
2026-05-04 23:04:34 +01:00
parent d82992f0ae
commit 9f2c8a6ab6
4 changed files with 50 additions and 6 deletions

View File

@@ -5,8 +5,11 @@ import {
publishSlackDisconnectedStatus,
startSlackSocketAndWaitForDisconnect,
} from "./provider-support.js";
import { formatSlackSocketReconnectMessage } from "./provider.js";
import { waitForSlackSocketDisconnect } from "./reconnect-policy.js";
import {
formatSlackSocketReconnectMessage,
formatSlackSocketStartRetryMessage,
} from "./provider.js";
import { formatUnknownError, waitForSlackSocketDisconnect } from "./reconnect-policy.js";
class FakeEmitter {
private listeners = new Map<string, Set<(...args: unknown[]) => void>>();
@@ -97,6 +100,28 @@ describe("slack socket reconnect helpers", () => {
).toBe("slack socket disconnected (disconnect); reconnecting in 2s (attempt 1/12)");
});
it("formats missing and unserializable socket errors without leaking undefined", () => {
const circular: Record<string, unknown> = {};
circular.self = circular;
expect(formatUnknownError(undefined)).toBe("unknown error");
expect(formatUnknownError(null)).toBe("unknown error");
expect(formatUnknownError("")).toBe("unknown error");
expect(formatUnknownError(new Error(""))).toBe("Error");
expect(formatUnknownError(circular)).toBe("unknown error");
});
it("formats socket start retries with an explicit reason field", () => {
expect(
formatSlackSocketStartRetryMessage({
attempt: 1,
maxAttempts: 12,
delayMs: 2_340,
error: undefined,
}),
).toBe('slack socket mode failed to start; retry 1/12 in 2s reason="unknown error"');
});
it("resolves disconnect waiter on socket disconnect event", async () => {
const client = new FakeEmitter();
const app = { receiver: { client } };

View File

@@ -97,6 +97,16 @@ export function formatSlackSocketReconnectMessage(params: {
return `slack socket disconnected (${params.event}); reconnecting in ${Math.round(params.delayMs / 1000)}s (attempt ${params.attempt}/${maxAttempts})${suffix}`;
}
export function formatSlackSocketStartRetryMessage(params: {
attempt: number;
maxAttempts: number;
delayMs: number;
error: unknown;
}) {
const maxAttempts = params.maxAttempts > 0 ? String(params.maxAttempts) : "∞";
return `slack socket mode failed to start; retry ${params.attempt}/${maxAttempts} in ${Math.round(params.delayMs / 1000)}s reason="${formatUnknownError(params.error)}"`;
}
function parseApiAppIdFromAppToken(raw?: string) {
const token = raw?.trim();
if (!token) {
@@ -534,7 +544,12 @@ export async function monitorSlackProvider(opts: MonitorSlackOpts = {}) {
}
const delayMs = computeBackoff(SLACK_SOCKET_RECONNECT_POLICY, reconnectAttempts);
runtime.error?.(
`slack socket mode failed to start. retry ${reconnectAttempts}/${SLACK_SOCKET_RECONNECT_POLICY.maxAttempts || "∞"} in ${Math.round(delayMs / 1000)}s (${formatUnknownError(err)})`,
formatSlackSocketStartRetryMessage({
attempt: reconnectAttempts,
maxAttempts: SLACK_SOCKET_RECONNECT_POLICY.maxAttempts,
delayMs,
error: err,
}),
);
try {
await sleepWithAbort(delayMs, opts.abortSignal);

View File

@@ -94,14 +94,17 @@ export function isNonRecoverableSlackAuthError(error: unknown): boolean {
}
export function formatUnknownError(error: unknown): string {
if (error === undefined || error === null) {
return "unknown error";
}
if (error instanceof Error) {
return error.message;
return error.message || error.name || "unknown error";
}
if (typeof error === "string") {
return error;
return error || "unknown error";
}
try {
return JSON.stringify(error);
return JSON.stringify(error) ?? "unknown error";
} catch {
return "unknown error";
}