mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-11 18:43:43 +00:00
Handle transient Slack request errors without crashing the gateway (openclaw#23787) thanks @graysurf
Verified: - pnpm install --frozen-lockfile - pnpm build - pnpm check - pnpm test:macmini Co-authored-by: graysurf <10785178+graysurf@users.noreply.github.com> Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
This commit is contained in:
@@ -94,6 +94,7 @@ Docs: https://docs.openclaw.ai
|
|||||||
- Cron/Schedule errors: notify users when a job is auto-disabled after repeated schedule computation failures. (#29098) Thanks .
|
- Cron/Schedule errors: notify users when a job is auto-disabled after repeated schedule computation failures. (#29098) Thanks .
|
||||||
- File tools/tilde paths: expand `~/...` against the user home directory before workspace-root checks in host file read/write/edit paths, while preserving root-boundary enforcement so outside-root targets remain blocked. (#29779) Thanks @Glucksberg.
|
- File tools/tilde paths: expand `~/...` against the user home directory before workspace-root checks in host file read/write/edit paths, while preserving root-boundary enforcement so outside-root targets remain blocked. (#29779) Thanks @Glucksberg.
|
||||||
- Slack/HTTP mode startup: treat Slack HTTP accounts as configured when `botToken` + `signingSecret` are present (without requiring `appToken`) in channel config/runtime status so webhook mode is not silently skipped. (#30567)
|
- Slack/HTTP mode startup: treat Slack HTTP accounts as configured when `botToken` + `signingSecret` are present (without requiring `appToken`) in channel config/runtime status so webhook mode is not silently skipped. (#30567)
|
||||||
|
- Slack/Transient request errors: classify Slack request-error messages like `Client network socket disconnected before secure TLS connection was established` as transient in unhandled-rejection fatal detection, preventing temporary network drops from crash-looping the gateway. (#23169)
|
||||||
- Slack/Usage footer formatting: wrap session keys in inline code in full response-usage footers so Slack does not parse colon-delimited session segments as emoji shortcodes. (#30258) Thanks @pushkarsingh32.
|
- Slack/Usage footer formatting: wrap session keys in inline code in full response-usage footers so Slack does not parse colon-delimited session segments as emoji shortcodes. (#30258) Thanks @pushkarsingh32.
|
||||||
- Slack/Socket Mode slash startup: treat `app.options()` registration as best-effort and fall back to static arg menus when listener registration fails, preventing Slack monitor startup crash loops on receiver init edge cases. (#21715)
|
- Slack/Socket Mode slash startup: treat `app.options()` registration as best-effort and fall back to static arg menus when listener registration fails, preventing Slack monitor startup crash loops on receiver init edge cases. (#21715)
|
||||||
- Slack/Legacy streaming config: map boolean `channels.slack.streaming=false` to unified streaming mode `off` (with `nativeStreaming=false`) so legacy configs correctly disable draft preview/native streaming instead of defaulting to `partial`. (#25990) Thanks @chilu18.
|
- Slack/Legacy streaming config: map boolean `channels.slack.streaming=false` to unified streaming mode `off` (with `nativeStreaming=false`) so legacy configs correctly disable draft preview/native streaming instead of defaulting to `partial`. (#25990) Thanks @chilu18.
|
||||||
|
|||||||
@@ -93,10 +93,22 @@ describe("installUnhandledRejectionHandler - fatal detection", () => {
|
|||||||
Object.assign(new Error("DNS resolve failed"), { code: "UND_ERR_DNS_RESOLVE_FAILED" }),
|
Object.assign(new Error("DNS resolve failed"), { code: "UND_ERR_DNS_RESOLVE_FAILED" }),
|
||||||
Object.assign(new Error("Connection reset"), { code: "ECONNRESET" }),
|
Object.assign(new Error("Connection reset"), { code: "ECONNRESET" }),
|
||||||
Object.assign(new Error("Timeout"), { code: "ETIMEDOUT" }),
|
Object.assign(new Error("Timeout"), { code: "ETIMEDOUT" }),
|
||||||
|
Object.assign(
|
||||||
|
new Error(
|
||||||
|
"A request error occurred: Client network socket disconnected before secure TLS connection was established",
|
||||||
|
),
|
||||||
|
{ code: "slack_webapi_request_error" },
|
||||||
|
),
|
||||||
Object.assign(new Error("A request error occurred: getaddrinfo EAI_AGAIN slack.com"), {
|
Object.assign(new Error("A request error occurred: getaddrinfo EAI_AGAIN slack.com"), {
|
||||||
code: "slack_webapi_request_error",
|
code: "slack_webapi_request_error",
|
||||||
original: { code: "EAI_AGAIN", syscall: "getaddrinfo", hostname: "slack.com" },
|
original: { code: "EAI_AGAIN", syscall: "getaddrinfo", hostname: "slack.com" },
|
||||||
}),
|
}),
|
||||||
|
Object.assign(new Error("A request error occurred: unknown"), {
|
||||||
|
code: "slack_webapi_request_error",
|
||||||
|
original: Object.assign(new Error("connect timeout"), {
|
||||||
|
code: "UND_ERR_CONNECT_TIMEOUT",
|
||||||
|
}),
|
||||||
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const transientErr of transientCases) {
|
for (const transientErr of transientCases) {
|
||||||
@@ -119,6 +131,17 @@ describe("installUnhandledRejectionHandler - fatal detection", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("exits on non-transient Slack request errors", () => {
|
||||||
|
const slackErr = Object.assign(
|
||||||
|
new Error("A request error occurred: invalid request payload"),
|
||||||
|
{
|
||||||
|
code: "slack_webapi_request_error",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
expectExitCodeFromUnhandled(slackErr, [1]);
|
||||||
|
});
|
||||||
|
|
||||||
it("does not exit on AbortError and logs suppression warning", () => {
|
it("does not exit on AbortError and logs suppression warning", () => {
|
||||||
const abortErr = new Error("This operation was aborted");
|
const abortErr = new Error("This operation was aborted");
|
||||||
abortErr.name = "AbortError";
|
abortErr.name = "AbortError";
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ const TRANSIENT_NETWORK_MESSAGE_CODE_RE =
|
|||||||
const TRANSIENT_NETWORK_MESSAGE_SNIPPETS = [
|
const TRANSIENT_NETWORK_MESSAGE_SNIPPETS = [
|
||||||
"getaddrinfo",
|
"getaddrinfo",
|
||||||
"socket hang up",
|
"socket hang up",
|
||||||
|
"client network socket disconnected before secure tls connection was established",
|
||||||
"network error",
|
"network error",
|
||||||
"network is unreachable",
|
"network is unreachable",
|
||||||
"temporary failure in name resolution",
|
"temporary failure in name resolution",
|
||||||
|
|||||||
Reference in New Issue
Block a user