diff --git a/packages/doorman-api/src/common/DoormanHandler.ts b/packages/doorman-api/src/common/DoormanHandler.ts index cf656cb..7953ab6 100644 --- a/packages/doorman-api/src/common/DoormanHandler.ts +++ b/packages/doorman-api/src/common/DoormanHandler.ts @@ -3,6 +3,7 @@ import { PrometheusContentType, Registry, Pushgateway, Summary, Counter, registe import { DoormanLambdaContext } from "./DoormanHandlerContext"; import { shouldBlockRequest } from "../utils/blockUserAgent"; import { RequestOptions } from "https"; +import { FastHttpPushgateway } from "../metrics/FastHttpPromGateway"; export type BaseEvent = { request: { cookies: {}; headers: {}; }; } @@ -44,7 +45,7 @@ export function withMetrics }, }; - const pushGateway = new Pushgateway(context.PUSHGATEWAY_URL, requestOptions, metricsRegistry); + const pushGateway = new FastHttpPushgateway(context.PUSHGATEWAY_URL, requestOptions, metricsRegistry); metricsRegistry.registerMetric(new Summary({ name: CommonMetrics.RUNTIME, @@ -111,7 +112,7 @@ export function withMetrics console.log(`[CommonHandler] there is ${remainingTime} ms left to send metrics`); let metricsTimeout = setTimeout(() => { - console.error("[CommonHandler] cutting it too close, abandoning metrics"); + console.log("[CommonHandler] cutting it too close, abandoning metrics"); callback(...result); }, remainingTime - 250); @@ -127,10 +128,8 @@ export function withMetrics }); console.log("[CommonHandler] pushed metrics successfully"); } catch (e: any) { - console.error("[CommonHandler] failed to push metrics, quietly discarding them", e); + console.log("[CommonHandler] failed to push metrics, quietly discarding them", e); } - - clearTimeout(metricsTimeout); callback(...result); diff --git a/packages/doorman-api/src/metrics/FastHttpPromGateway.ts b/packages/doorman-api/src/metrics/FastHttpPromGateway.ts new file mode 100644 index 0000000..bbbee29 --- /dev/null +++ b/packages/doorman-api/src/metrics/FastHttpPromGateway.ts @@ -0,0 +1,90 @@ +import { Pushgateway, Registry, RegistryContentType } from "prom-client"; +import url from "url"; +import http from "http"; +import https from "https"; +import { gzipSync } from "zlib"; + +// copied mostly from pushgateway.js implementation. Just swapping out the http call to not await a response + +export class FastHttpPushgateway extends Pushgateway { + constructor(url: string, options?: any, registry?: Registry) { + super(url, options, registry); + } + + override push(params: Pushgateway.Parameters): Promise<{ resp?: unknown; body?: unknown; }> { + let method = "PUT"; + let job = params.jobName; + let groupings = params.groupings; + + // @ts-ignore + let gatewayUrl: string = this.gatewayUrl; + // @ts-ignore + let requestOptions: any = this.requestOptions; + + // @ts-ignore + let registry: Registry = this.registry; + + // `URL` first added in v6.13.0 + // eslint-disable-next-line n/no-deprecated-api + const gatewayUrlParsed = url.parse(gatewayUrl); + const gatewayUrlPath = + gatewayUrlParsed.pathname && gatewayUrlParsed.pathname !== '/' + ? gatewayUrlParsed.pathname + : ''; + const jobPath = job + ? `/job/${encodeURIComponent(job)}${generateGroupings(groupings)}` + : ''; + const path = `${gatewayUrlPath}/metrics${jobPath}`; + + // eslint-disable-next-line n/no-deprecated-api + const target = url.resolve(gatewayUrl, path); + // eslint-disable-next-line n/no-deprecated-api + const requestParams = url.parse(target); + const httpModule = isHttps(requestParams.href) ? https : http; + const options = Object.assign(requestParams, requestOptions, { + method, + }); + + return new Promise((resolve, reject) => { + if (method === 'DELETE' && options.headers) { + delete options.headers['Content-Encoding']; + } + const req = httpModule.request(options); + + // write metrics + registry + .metrics() + .then(metrics => { + if ( + options.headers && + options.headers['Content-Encoding'] === 'gzip' + ) { + metrics = gzipSync(metrics) as any; + } + + // write metrics, and once thats done, end req. Don't wait for response + req.write(metrics, () => { + req.end(() => { + resolve({}); + }); + }); + }) + }); + } +} + +function generateGroupings(groupings: any) { + if (!groupings) { + return ''; + } + return Object.keys(groupings) + .map( + key => + `/${encodeURIComponent(key)}/${encodeURIComponent(groupings[key])}`, + ) + .join(''); +} + +function isHttps(href: string) { + return href.search(/^https/) !== -1; +} diff --git a/packages/doorman-client/src/functions/buzzer-activated.ts b/packages/doorman-client/src/functions/buzzer-activated.ts index 27aa93f..3ea41d5 100644 --- a/packages/doorman-client/src/functions/buzzer-activated.ts +++ b/packages/doorman-client/src/functions/buzzer-activated.ts @@ -135,11 +135,11 @@ export const handler: ServerlessFunctionSignature