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 179 days ago Viewed 16618 times
0
Submitted by hugo697 Deno
Verified 179 days ago
1
import { WebClient } from "https://deno.land/x/slack_web_api@1.0.0/mod.ts";
2
import dayjs from "npm:dayjs";
3

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

8
function formatError(error: any) {
9
  if (error.stack && error.name && error.message) {
10
    return `*${error.name}: ${error.message}*\`\`\`\n${error.stack}\n\`\`\``;
11
  } else {
12
    return `\`\`\`\n${JSON.stringify(error, null, 2)}\n\`\`\``;
13
  }
14
}
15

16
export async function main(
17
  workspace_id: string,
18
  job_id: string, // The UUID of the job that errored
19
  path: string, // The path of the script or flow that errored
20
  is_flow: boolean, // Whether the runnable is a flow
21
  schedule_path: string, // The path of the schedule
22
  error: object, // The error details
23
  started_at: string, // The start datetime of the latest job that failed
24
  failed_times: number, // Minimum number of times the schedule failed before calling the error handler
25
  slack: Slack,
26
  channel: string,
27
) {
28
  const baseUrl = Deno.env.get("WM_BASE_URL");
29
  const scheduleUrl = baseUrl + "/runs?schedule_path=" +
30
    encodeURIComponent(schedule_path) + "&workspace=" + encodeURIComponent(workspace_id);
31
  const scriptOrFlowRunUrl = baseUrl + (is_flow ? "/flows/get/" : "/scripts/get/") +
32
    path + "?workspace=" + encodeURIComponent(workspace_id);
33
  const web = new WebClient(slack.token);
34
  const jobRunUrl = baseUrl + "/run/" + job_id + "?workspace=" + encodeURIComponent(workspace_id);
35

36
  let rawText = ""
37
  if (schedule_path === undefined) {
38
    rawText = `${schedule_path != undefined ? `Schedule ${schedule_path} failed ` : ""}${failed_times > 1 ? (failed_times + " times in a row") : ""}`
39
  } else {
40
    rawText = `Run <${jobRunUrl}|${job_id}> of ${is_flow ? "flow" : "script"}: <${scriptOrFlowRunUrl}|${path}> failed ${failed_times > 1 ? (failed_times + " times in a row") : ""}`
41
  }
42

43
  let mdText = ""
44
  if (schedule_path === undefined) {
45
    mdText = `*Run <${jobRunUrl}|${job_id}> of ${is_flow ? "flow" : "script"} <${scriptOrFlowRunUrl}|${path}> failed*${failed_times > 1 ? (" " + failed_times + " times in a row") : ""}:`
46
  } else {
47
    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}>`
48
  }
49

50
  await web.chat.postMessage({
51
    channel,
52
    text: rawText,
53
    blocks: [
54
      {
55
        "type": "section",
56
        "text": {
57
          "type": "mrkdwn",
58
          "text": mdText,
59
        },
60
      },
61
    ],
62
    attachments: [
63
      {
64
        color: "#ff0000",
65
        "blocks": [{
66
          "type": "section",
67
          "text": {
68
            "type": "mrkdwn",
69
            "text": `Last failure at: ${
70
              dayjs(started_at).format("DD.MM.YYYY HH:mm (Z)")
71
            }\n${formatError(error)}`,
72
          },
73
        }],
74
      },
75
    ],
76
  });
77
}
78