From cc408ab0fe06f515447f5189001dbb88f6d8accb Mon Sep 17 00:00:00 2001 From: Martin Dimitrov Date: Sun, 2 Feb 2025 13:01:45 -0800 Subject: [PATCH] add metrics to notify route --- .../src/functions/api/door/notify.ts | 22 +++++++++++++--- .../doorman-api/src/metrics/NotifyMetrics.ts | 25 +++++++++++++++++++ packages/doorman-api/src/utils/discord.ts | 21 ++++++---------- 3 files changed, 52 insertions(+), 16 deletions(-) create mode 100644 packages/doorman-api/src/metrics/NotifyMetrics.ts diff --git a/packages/doorman-api/src/functions/api/door/notify.ts b/packages/doorman-api/src/functions/api/door/notify.ts index 67eb7fb..c564604 100644 --- a/packages/doorman-api/src/functions/api/door/notify.ts +++ b/packages/doorman-api/src/functions/api/door/notify.ts @@ -1,6 +1,9 @@ import { ServerlessEventObject, ServerlessFunctionSignature } from "@twilio-labs/serverless-runtime-types/types"; import { TwilioContext } from "../../../types/TwilioContext"; import { jsonMsgSuffix, sendMessageToUser } from "../../../utils/discord"; +import { getMetricFromRegistry, withMetrics } from "../../../common/DoormanHandler"; +import { NotifyMetrics, registerMetrics } from "../../../metrics/NotifyMetrics"; +import { Counter, Summary } from "prom-client"; export interface NotifyRequest extends ServerlessEventObject { @@ -12,9 +15,11 @@ export interface NotifyRequest extends ServerlessEventObject { json: string; } -export const handler: ServerlessFunctionSignature = async function(context, event, callback) { +export const handler: ServerlessFunctionSignature = withMetrics('notify', async (context, event, callback, metricsRegistry) => { const response = new Twilio.Response(); + registerMetrics(metricsRegistry); + let users: string[]; let msgs: string[]; let jsons: string[]; @@ -27,12 +32,22 @@ export const handler: ServerlessFunctionSignature jsons = JSON.parse(event.json); console.log("after parsing", event.json); + const recordNotifyLatency = getMetricFromRegistry(metricsRegistry, NotifyMetrics.DISCORD_LATENCY) + .startTimer(); + promises = msgs.map((msg, i) => sendMessageToUser( context, users[i], msg + jsonMsgSuffix(jsons[i]) - ).catch((e: Error) => console.error(e)) + ) + .then(() => { + recordNotifyLatency(); + }) + .catch((e: Error) => { + recordNotifyLatency(); + getMetricFromRegistry(metricsRegistry, NotifyMetrics.DISCORD_FAILURE).inc({ error: e.name }, 1); + }) ); } catch (e) { console.error(e); @@ -45,10 +60,11 @@ export const handler: ServerlessFunctionSignature let timer = setTimeout(() => { console.log("Ungraceful finish: running out of time"); + getMetricFromRegistry(metricsRegistry, NotifyMetrics.NOTIFY_TIMEOUT).inc(1); callback(null, response); }, 9500); await Promise.all(promises); clearTimeout(timer); return callback(null, response); -}; +}); diff --git a/packages/doorman-api/src/metrics/NotifyMetrics.ts b/packages/doorman-api/src/metrics/NotifyMetrics.ts new file mode 100644 index 0000000..030bbbb --- /dev/null +++ b/packages/doorman-api/src/metrics/NotifyMetrics.ts @@ -0,0 +1,25 @@ +import { Counter, Registry, Summary } from "prom-client"; + +export enum NotifyMetrics { + DISCORD_LATENCY = "DiscordLatency", + DISCORD_FAILURE = "DiscordFailure", + NOTIFY_TIMEOUT = "NotifyTimeout" +} + +export const registerMetrics = (metricsRegistry: Registry) => { + metricsRegistry.registerMetric(new Summary({ + name: NotifyMetrics.DISCORD_LATENCY, + help: "Latency for the Discord API", + })); + + metricsRegistry.registerMetric(new Counter({ + name: NotifyMetrics.DISCORD_FAILURE, + help: "Failure calling discord API", + labelNames: ['error'], + })); + + metricsRegistry.registerMetric(new Counter({ + name: NotifyMetrics.NOTIFY_TIMEOUT, + help: "Timeout before all notify calls completed", + })); +} diff --git a/packages/doorman-api/src/utils/discord.ts b/packages/doorman-api/src/utils/discord.ts index 6829ab8..7313d23 100644 --- a/packages/doorman-api/src/utils/discord.ts +++ b/packages/doorman-api/src/utils/discord.ts @@ -33,20 +33,15 @@ export const sendMessageToUser = async ( userId: string, msg: string, ) => { - try { - const client = await getDiscordClient(context); - if (userCache[userId] === undefined) { - console.log("[UserCache] cache miss for", userId); - userCache[userId] = await client.users.fetch(userId); - } else { - console.log("[UserCache] cache hit for", userId); - } - const user = userCache[userId]; - return user.send(msg); - } catch (e) { - console.log(e); - console.log(`Failed to send msg to ${userId}`); + const client = await getDiscordClient(context); + if (userCache[userId] === undefined) { + console.log("[UserCache] cache miss for", userId); + userCache[userId] = await client.users.fetch(userId); + } else { + console.log("[UserCache] cache hit for", userId); } + const user = userCache[userId]; + return user.send(msg); }; export const jsonMsgSuffix = (jsonString: string = "") => {