From 7a2ebb92beaabc823b2a5099edd9029e6c5a12c0 Mon Sep 17 00:00:00 2001 From: Martin Dimitrov Date: Tue, 4 Mar 2025 11:35:54 -0800 Subject: [PATCH] add fail fast to the common doorman lambda --- bun.lockb | Bin 429472 -> 430304 bytes packages/doorman-api/package.json | 3 +- .../doorman-api/src/common/DoormanHandler.ts | 79 ++++++++++++++++-- packages/doorman-client/package.json | 3 +- .../src/functions/buzzer-activated.ts | 30 +++---- 5 files changed, 93 insertions(+), 22 deletions(-) diff --git a/bun.lockb b/bun.lockb index 5ca2f056ad98ccb12d217e29d05aec4c31b340bd..12921d98002383fd4b424b382b911aac75d0157f 100755 GIT binary patch delta 23944 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 diff --git a/packages/doorman-api/package.json b/packages/doorman-api/package.json index 7707587..6382487 100644 --- a/packages/doorman-api/package.json +++ b/packages/doorman-api/package.json @@ -12,10 +12,11 @@ }, "dependencies": { "@aws-sdk/client-dynamodb": "^3.609.0", - "@twilio-labs/serverless-runtime-types": "^3.0.0", + "@twilio-labs/serverless-runtime-types": "^4.0.1", "@twilio/runtime-handler": "1.3.0", "discord.js": "^14.16.3", "prom-client": "^15.1.3", + "promise.timeout": "^1.2.0", "twilio": "^3.56", "winston": "^3.17.0", "winston-loki": "^6.1.3" diff --git a/packages/doorman-api/src/common/DoormanHandler.ts b/packages/doorman-api/src/common/DoormanHandler.ts index e02fa62..764ad68 100644 --- a/packages/doorman-api/src/common/DoormanHandler.ts +++ b/packages/doorman-api/src/common/DoormanHandler.ts @@ -4,19 +4,27 @@ import { DoormanLambdaContext } from "./DoormanHandlerContext"; import { shouldBlockRequest } from "../utils/blockUserAgent"; import { RequestOptions } from "https"; import { FastHttpPushgateway } from "../metrics/FastHttpPromGateway"; +import '@twilio-labs/serverless-runtime-types'; +import VoiceResponse from 'twilio/lib/twiml/VoiceResponse'; import { createLogger, format, Logger, transports } from "winston"; import LokiTransport from "winston-loki"; +import pTimeout, { TimeoutError } from "promise.timeout"; export type BaseEvent = { request: { cookies: {}; headers: {}; }; } +export type CallbackResult = Parameters; +export type FailFastCallback = () => CallbackResult; + export type DoormanLambda = ( context: Parameters>[0], event: Parameters>[1], callback: Parameters>[2], metricsRegistry: Registry, logger: Logger, -) => void; + // this is optional, but if called this method should provide an alternative callback provider that can fail fast + failFastCallback: (fn: FailFastCallback) => void, +) => Promise; export enum CommonMetrics { RUNTIME = "FunctionRuntime", @@ -25,6 +33,9 @@ export enum CommonMetrics { LOKI_ERROR = "LokiError", LOKI_LOG_AFTER_CLOSE = "LokiLogAfterClose", TWILIO_ISOLATION_BUSTED = "TwilioIsolationBusted", + INNER_HANDLER_TIMEOUT = "InnerHandlerTimeout", + INNER_HANDLER_MISSING_FAIL_FAST = "InnerHandlerMissingFailFast", + RETURN_FALLBACK_RESPONSE = "ReturnFallbackResponse", }; export function getMetricFromRegistry(metricsRegistry: Registry, metric: string): T { @@ -42,8 +53,15 @@ export function gracefullyEndLogger(logger: Logger): Promise { }); } +// TODO: make this response a voice message? +const REJECT_RESPONSE = new VoiceResponse(); +REJECT_RESPONSE.reject(); + +const FALLBACK_CALLBACK: CallbackResult = [null, REJECT_RESPONSE]; + const MINIMUM_MS_TO_SEND_RESPONSE: number = 250; const FUNCTION_MAXIMUM_DURATION_MS: number = 10_000; +const INNER_HANDLER_MAXIMUM_DURATION_MS: number = 8_500; /** * A decorator for twilio handlers. It provides a metrics registry and @@ -100,6 +118,21 @@ export function withMetrics help: "Twilio invocation lasted longer than 10s", })); + metricsRegistry.registerMetric(new Counter({ + name: CommonMetrics.INNER_HANDLER_MISSING_FAIL_FAST, + help: "Inner handler was timed out and we did not have any fallback response", + })); + + metricsRegistry.registerMetric(new Counter({ + name: CommonMetrics.INNER_HANDLER_TIMEOUT, + help: "Inner handler was timed out", + })); + + metricsRegistry.registerMetric(new Counter({ + name: CommonMetrics.RETURN_FALLBACK_RESPONSE, + help: "Common handler returned a fallback response", + })); + // Create a Winston logger const logger = createLogger({ level: 'info', @@ -136,6 +169,7 @@ export function withMetrics // Override the base console log with winston console.log = function (...args) { if (logger.writable) { + // @ts-ignore return logger.info.apply(logger, [...args]); } getMetricFromRegistry(metricsRegistry, CommonMetrics.LOKI_LOG_AFTER_CLOSE).inc(1); @@ -143,6 +177,7 @@ export function withMetrics }; console.error = function (...args) { if (logger.writable) { + // @ts-ignore return logger.error.apply(logger, [...args]); } getMetricFromRegistry(metricsRegistry, CommonMetrics.LOKI_LOG_AFTER_CLOSE).inc(1); @@ -150,6 +185,7 @@ export function withMetrics }; console.warn = function (...args) { if (logger.writable) { + // @ts-ignore return logger.warn.apply(logger, [...args]); } getMetricFromRegistry(metricsRegistry, CommonMetrics.LOKI_LOG_AFTER_CLOSE).inc(1); @@ -157,6 +193,7 @@ export function withMetrics }; console.info = function (...args) { if (logger.writable) { + // @ts-ignore return logger.info.apply(logger, [...args]); } getMetricFromRegistry(metricsRegistry, CommonMetrics.LOKI_LOG_AFTER_CLOSE).inc(1); @@ -175,6 +212,12 @@ export function withMetrics callbackResult = [err, payload]; } + // intercept the fail fast callback method, if it is provided + let failFastCallbackMethod: FailFastCallback | undefined; + const failFastCallbackProvider: (fn: FailFastCallback) => void = (fn) => { + failFastCallbackMethod = fn; + } + // block requests before we even call the handler if (shouldBlockRequest(event)) { getMetricFromRegistry(metricsRegistry, CommonMetrics.BLOCKED_REQUEST).inc(1); @@ -182,14 +225,34 @@ export function withMetrics response.setStatusCode(200); callbackResult = [null, response]; } else { - await handler(context, event, tempCallback, metricsRegistry, logger); + // wait for response for up to x ms, otherwise we call the failFastCallbackMethod + try { + await pTimeout( + () => handler(context, event, tempCallback, metricsRegistry, logger, failFastCallbackProvider), + INNER_HANDLER_MAXIMUM_DURATION_MS + )(); + } catch (e) { + console.log(e); + if (e instanceof TimeoutError) { + getMetricFromRegistry(metricsRegistry, CommonMetrics.INNER_HANDLER_TIMEOUT).inc(1); + + if (!failFastCallbackMethod) { + getMetricFromRegistry(metricsRegistry, CommonMetrics.INNER_HANDLER_MISSING_FAIL_FAST).inc(1); + reject("Timeout, but no failfast result was given"); + return; + } + + callbackResult = failFastCallbackMethod(); + } + } } if (!callbackResult) { reject("No callback was given"); + return; } - let statusCode: number | undefined = (callbackResult?.[1] as any)?.statusCode; + let statusCode: number | undefined = (callbackResult[1] as any)?.statusCode; if (statusCode && statusCode >= 400) { getMetricFromRegistry(metricsRegistry, CommonMetrics.HTTP_CLIENT_ERROR).inc({ @@ -197,12 +260,16 @@ export function withMetrics }, 1); } - resolve(callbackResult as Parameters); + resolve(callbackResult); }); console.time("[CommonHandler] nested handler time"); - const result = await handlerResponsePromise; + const result = await handlerResponsePromise.catch((err) => { + console.error("[CommonHandler] inner handler promise was rejected with reason: " + err); + getMetricFromRegistry(metricsRegistry, CommonMetrics.RETURN_FALLBACK_RESPONSE).inc(1); + return FALLBACK_CALLBACK; + }); console.timeEnd("[CommonHandler] nested handler time"); @@ -214,7 +281,7 @@ export function withMetrics getMetricFromRegistry(metricsRegistry, CommonMetrics.TWILIO_ISOLATION_BUSTED).inc(1); } - // abandoning metrics, since there isn't enough time + // abandoning metrics/logs, since there isn't enough time if (remainingTime <= MINIMUM_MS_TO_SEND_RESPONSE) { console.error("[CommonHandler] there is no time to send metrics / logs abandoning them"); callback(...result); diff --git a/packages/doorman-client/package.json b/packages/doorman-client/package.json index 6e4f891..c90d1b9 100644 --- a/packages/doorman-client/package.json +++ b/packages/doorman-client/package.json @@ -11,11 +11,12 @@ "deploy": "twilio-run deploy --load-system-env --env .env.example --service-name buzzer --environment=prod --override-existing-project" }, "dependencies": { - "@twilio-labs/serverless-runtime-types": "^3.0.0", + "@twilio-labs/serverless-runtime-types": "^4.0.1", "@twilio/runtime-handler": "1.3.0", "node-fetch": "^2.7.0", "prom-client": "^15.1.3", "prometheus-remote-write": "^0.5.0", + "promise.timeout": "^1.2.0", "twilio": "^3.84.1", "winston": "^3.17.0", "winston-loki": "^6.1.3" diff --git a/packages/doorman-client/src/functions/buzzer-activated.ts b/packages/doorman-client/src/functions/buzzer-activated.ts index 1ccf3d7..70fe6a9 100644 --- a/packages/doorman-client/src/functions/buzzer-activated.ts +++ b/packages/doorman-client/src/functions/buzzer-activated.ts @@ -19,7 +19,7 @@ import { getMetricFromRegistry, withMetrics } from '../../../doorman-api/src/com import { Counter, Summary } from 'prom-client'; import { BuzzerActivatedMetrics, registerMetrics } from '../metrics/BuzzerActivatedMetrics'; -export const handler: ServerlessFunctionSignature = withMetrics('buzzer-activated', async function(context, event, callback, metricsRegistry) { +export const handler: ServerlessFunctionSignature = withMetrics('buzzer-activated', async function(context, event, callback, metricsRegistry, logger, failFastCallback) { // metrics registerMetrics(metricsRegistry); @@ -58,7 +58,7 @@ export const handler: ServerlessFunctionSignature ""), metricsRegistry); - let discordLock = false; + let responseLock = false; let intervals: Timer[] = []; let timeouts: Timer[] = []; @@ -79,8 +79,8 @@ export const handler: ServerlessFunctionSignature { const twiml = dialFallbackTwiml(config); - if (!discordLock) { - discordLock = true; + if (!responseLock) { + responseLock = true; getMetricFromRegistry(metricsRegistry, BuzzerActivatedMetrics.DIAL_THROUGH) .inc({ door: config.door }, 1); @@ -120,15 +120,18 @@ export const handler: ServerlessFunctionSignature((resolve, reject) => { - timeouts.push(setTimeout(async () => { - getMetricFromRegistry(metricsRegistry, BuzzerActivatedMetrics.RESULT_NOTIFICATION_FATE_UNKNOWN) + // provide a method to the decorator to use as a fast fallback that shouldn't have any await + failFastCallback(() => { + // prevent other responses + responseLock = true; + + getMetricFromRegistry(metricsRegistry, BuzzerActivatedMetrics.RESULT_NOTIFICATION_FATE_UNKNOWN) .inc({ door: config.door }, 1); getMetricFromRegistry(metricsRegistry, BuzzerActivatedMetrics.DIAL_THROUGH) @@ -136,13 +139,12 @@ export const handler: ServerlessFunctionSignature clearTimeout(timeout)); intervals.forEach(interval => clearInterval(interval));