0
Workspace or Schedule error handler Failure
One script reply has been approved by the moderators Verified

Error handler script sending an error message to a Slack channel. It can be used for both a global workspace error handler and specific schedules error handlers

Created by hugo697 415 days ago Viewed 62752 times
0
Submitted by hugo697 Bun
Verified 101 days ago
1
import { WebClient } from "@slack/web-api";
2
import dayjs from "dayjs";
3

4
type Slack = {
5
  token: string;
6
};
7

8
function formatError(error: any) {
9
  if (error.stack && error.name && error.message) {
10
    const formatted = `*${error.name}: ${error.message}*\`\`\`\n${error.stack}\n\`\`\``;
11
    if (formatted.length > 2900) {
12
      return `\`\`\`\n${JSON.stringify(error, null, 2).substring(0, 2900)}...\n(truncated)\n\`\`\``;
13
    } else {
14
      return formatted
15
    }
16
  } else {
17
    const stringified = JSON.stringify(error, null, 2);
18
    if (stringified.length > 2900) {
19
      return `\`\`\`\n${stringified.substring(0, 2900)}...\n(truncated)\n\`\`\``;
20
    } else {
21
      return `\`\`\`\n${stringified}\n\`\`\``;
22
    }
23
  }
24
}
25

26
export async function main(
27
  workspace_id: string,
28
  job_id: string, // The UUID of the job that errored
29
  path: string, // The path of the script or flow that errored
30
  is_flow: boolean, // Whether the runnable is a flow
31
  schedule_path: string, // The path of the schedule
32
  error: object, // The error details
33
  started_at: string, // The start datetime of the latest job that failed
34
  failed_times: number, // Minimum number of times the schedule failed before calling the error handler
35
  slack: Slack,
36
  channel: string,
37
) {
38
  const baseUrl = process.env["WM_BASE_URL"];
39
  const scheduleUrl = baseUrl + "/runs?schedule_path=" +
40
    encodeURIComponent(schedule_path) + "&workspace=" + encodeURIComponent(workspace_id);
41
  const scriptOrFlowRunUrl = baseUrl + (is_flow ? "/flows/get/" : "/scripts/get/") +
42
    path + "?workspace=" + encodeURIComponent(workspace_id);
43
  const web = new WebClient(slack.token);
44
  const jobRunUrl = baseUrl + "/run/" + job_id + "?workspace=" + encodeURIComponent(workspace_id);
45

46
  let rawText = ""
47
  if (schedule_path === undefined) {
48
    rawText = `${schedule_path != undefined ? `Schedule ${schedule_path} failed ` : ""}${failed_times > 1 ? (failed_times + " times in a row") : ""}`
49
  } else {
50
    rawText = `Run <${jobRunUrl}|${job_id}> of ${is_flow ? "flow" : "script"}: <${scriptOrFlowRunUrl}|${path}> failed ${failed_times > 1 ? (failed_times + " times in a row") : ""}`
51
  }
52

53
  let mdText = ""
54
  if (schedule_path === undefined) {
55
    mdText = `*Run <${jobRunUrl}|${job_id}> of ${is_flow ? "flow" : "script"} <${scriptOrFlowRunUrl}|${path}> failed*${failed_times > 1 ? (" " + failed_times + " times in a row") : ""}:`
56
  } else {
57
    mdText = `*Schedule <${scheduleUrl}|${schedule_path}> failed*${failed_times > 1 ? (" " + failed_times + " times in a row") : ""}:\n- Run <${jobRunUrl}|${job_id}> of ${is_flow ? "flow" : "script"}: <${scriptOrFlowRunUrl}|${path}>`
58
  }
59

60
  const errorText = `Last failure at: ${dayjs(started_at).format("DD.MM.YYYY HH:mm (Z)")
61
    }\n${formatError(error)}`
62

63
  await web.chat.postMessage({
64
    channel,
65
    text: rawText,
66
    blocks: [
67
      {
68
        "type": "section",
69
        "text": {
70
          "type": "mrkdwn",
71
          "text": mdText,
72
        },
73
      },
74
    ],
75
    attachments: [
76
      {
77
        color: "#ff0000",
78
        "blocks": [{
79
          "type": "section",
80
          "text": {
81
            "type": "mrkdwn",
82
            "text": errorText,
83
          },
84
        }],
85
        fallback: errorText
86
      },
87
    ],
88
  });
89
}
Other submissions