From 3311e9d354582e88333cddc5504e7c019c550d0f Mon Sep 17 00:00:00 2001 From: Nawaz Dhandala Date: Sun, 28 Dec 2025 13:33:52 +0000 Subject: [PATCH] refactor: update metrics endpoint to return pending monitor count for KEDA autoscaling --- Probe/API/Metrics.ts | 31 ++++++++++++-------- ProbeIngest/API/Monitor.ts | 58 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 12 deletions(-) diff --git a/Probe/API/Metrics.ts b/Probe/API/Metrics.ts index 9864276077..ab39c56060 100644 --- a/Probe/API/Metrics.ts +++ b/Probe/API/Metrics.ts @@ -19,6 +19,7 @@ import ProxyConfig from "../Utils/ProxyConfig"; const router: ExpressRouter = Express.getRouter(); // Metrics endpoint for Keda autoscaling +// Returns the number of monitors pending to be probed by this probe router.get( "/queue-size", async ( @@ -28,11 +29,14 @@ router.get( ): Promise => { try { // Get the pending monitor count for this specific probe from ProbeIngest API - const queueSizeUrl: URL = URL.fromString( + // This is the correct metric - the number of monitors waiting to be probed + const pendingMonitorsUrl: URL = URL.fromString( PROBE_INGEST_URL.toString(), - ).addRoute("/metrics/queue-size"); + ).addRoute("/monitor/pending-count"); - logger.debug("Fetching queue size from ProbeIngest API"); + logger.debug( + "Fetching pending monitor count from ProbeIngest API for KEDA scaling", + ); // Use probe authentication (probe key and probe ID) const requestBody: JSONObject = ProbeAPIRequest.getDefaultRequestBody(); @@ -40,37 +44,40 @@ router.get( const result: HTTPResponse | HTTPErrorResponse = await API.fetch({ method: HTTPMethod.POST, - url: queueSizeUrl, + url: pendingMonitorsUrl, data: requestBody, headers: {}, - options: { ...ProxyConfig.getRequestProxyAgents(queueSizeUrl) }, + options: { ...ProxyConfig.getRequestProxyAgents(pendingMonitorsUrl) }, }); if (result instanceof HTTPErrorResponse) { - logger.error("Error fetching queue size from ProbeIngest API"); + logger.error("Error fetching pending monitor count from ProbeIngest API"); logger.error(result); throw result; } - logger.debug("Queue size fetched successfully from ProbeIngest API"); + logger.debug( + "Pending monitor count fetched successfully from ProbeIngest API", + ); logger.debug(result.data); - // Extract queueSize from the response - let queueSize: number = (result.data["queueSize"] as number) || 0; + // Extract count from the response - this is the number of monitors pending to be probed + let queueSize: number = (result.data["count"] as number) || 0; // if string then convert to number - if (typeof queueSize === "string") { const parsedQueueSize: number = parseInt(queueSize, 10); if (!isNaN(parsedQueueSize)) { queueSize = parsedQueueSize; } else { - logger.warn("Queue size is not a valid number, defaulting to 0"); + logger.warn( + "Pending monitor count is not a valid number, defaulting to 0", + ); queueSize = 0; } } - logger.debug(`Queue size fetched: ${queueSize}`); + logger.debug(`Pending monitor count for KEDA: ${queueSize}`); return Response.sendJsonObjectResponse(req, res, { queueSize: queueSize, diff --git a/ProbeIngest/API/Monitor.ts b/ProbeIngest/API/Monitor.ts index 85279de752..84619d626a 100644 --- a/ProbeIngest/API/Monitor.ts +++ b/ProbeIngest/API/Monitor.ts @@ -277,6 +277,64 @@ router.get( }, ); +// This API returns the count of monitors pending to be probed for the authenticated probe. +// Used by KEDA for autoscaling probes based on pending monitor count. +router.post( + "/monitor/pending-count", + ProbeAuthorization.isAuthorizedServiceMiddleware, + async ( + req: ExpressRequest, + res: ExpressResponse, + next: NextFunction, + ): Promise => { + try { + if ( + !(req as ProbeExpressRequest).probe || + !(req as ProbeExpressRequest).probe?.id + ) { + logger.error("Probe not found for pending-count request"); + + return Response.sendErrorResponse( + req, + res, + new BadDataException("Probe not found"), + ); + } + + const probeId: ObjectID = (req as ProbeExpressRequest).probe!.id!; + + if (!probeId) { + logger.error("Probe ID not found for pending-count request"); + + return Response.sendErrorResponse( + req, + res, + new BadDataException("Probe not found"), + ); + } + + // Get count of monitors pending to be probed + const monitorProbesCount: PositiveNumber = + await MonitorProbeService.countBy({ + query: getMonitorFetchQuery(probeId), + props: { + isRoot: true, + }, + }); + + logger.debug( + `Pending monitor count for probe ${probeId.toString()}: ${monitorProbesCount.toNumber()}`, + ); + + return Response.sendJsonObjectResponse(req, res, { + count: monitorProbesCount.toNumber(), + }); + } catch (err) { + return next(err); + } + }, +); + router.post( "/monitor/list", ProbeAuthorization.isAuthorizedServiceMiddleware,