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, |
29 | path: string, |
30 | is_flow: boolean, |
31 | schedule_path: string, |
32 | error: object, |
33 | started_at: string, |
34 | failed_times: number, |
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 | } |