From 3d5767b60b7eac5228cdca413c870986f273c5f1 Mon Sep 17 00:00:00 2001 From: Torben Sorensen Date: Mon, 22 Dec 2025 18:58:01 -0800 Subject: [PATCH] roll back changes to src/routes/system.routes.ts hopefully before OOM issues --- src/routes/system.routes.ts | 50 ++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/src/routes/system.routes.ts b/src/routes/system.routes.ts index 3b52c757..780c79aa 100644 --- a/src/routes/system.routes.ts +++ b/src/routes/system.routes.ts @@ -1,4 +1,4 @@ -// src/routes/system.routests +// src/routes/system.routes.ts import { Router, Request, Response, NextFunction } from 'express'; import { exec } from 'child_process'; import { z } from 'zod'; @@ -8,7 +8,7 @@ import { validateRequest } from '../middleware/validation.middleware'; const router = Router(); -// Validation Schemas +// Helper for consistent required string validation (handles missing/null/empty) const requiredString = (message: string) => z.preprocess((val) => val ?? '', z.string().min(1, message)); @@ -18,65 +18,62 @@ const geocodeSchema = z.object({ }), }); +// An empty schema for routes that do not expect any input, to maintain a consistent validation pattern. const emptySchema = z.object({}); /** - * GET /pm2-status - * Checks if 'flyer-crawler-api' is online via PM2. + * Checks the status of the 'flyer-crawler-api' process managed by PM2. + * This is intended for development and diagnostic purposes. */ router.get( '/pm2-status', validateRequest(emptySchema), (req: Request, res: Response, next: NextFunction) => { - // Using simple exec command - const cmd = 'pm2 describe flyer-crawler-api'; - - exec(cmd, (error, stdout, stderr) => { - if (res.headersSent) return; - - // Handle "process not found" case which might come as an error code OR text - const output = (stdout || '') + (stderr || ''); - const processNotFound = output.includes("doesn't exist"); - + // The name 'flyer-crawler-api' comes from your ecosystem.config.cjs file. + exec('pm2 describe flyer-crawler-api', (error, stdout, stderr) => { if (error) { - if (processNotFound) { - logger.warn('[API /pm2-status] PM2 process not found.'); + // 'pm2 describe' exits with an error if the process is not found. + // We can treat this as a "fail" status for our check. + if (stdout && stdout.includes("doesn't exist")) { + logger.warn('[API /pm2-status] PM2 process "flyer-crawler-api" not found.'); return res.json({ success: false, message: 'Application process is not running under PM2.', }); } - - logger.error({ err: error.message }, '[API /pm2-status] Exec error'); + logger.error( + { error: stderr || error.message }, + '[API /pm2-status] Error executing pm2 describe:', + ); return next(error); } - // Treat stderr as error if it contains text (PM2 often outputs warnings here) + // Check if there was output to stderr, even if the exit code was 0 (success). + // This handles warnings or non-fatal errors that should arguably be treated as failures in this context. if (stderr && stderr.trim().length > 0) { - // Special case: if it's just a warning we might want to ignore, but sticking to defensive rules: - logger.error({ stderr }, '[API /pm2-status] Stderr output'); + logger.error({ stderr }, '[API /pm2-status] PM2 executed but produced stderr:'); return next(new Error(`PM2 command produced an error: ${stderr}`)); } - // Check for online status in the table output - const isOnline = /│ status\s+│ online\s+│/m.test(stdout || ''); + // If the command succeeds, we can parse stdout to check the status. + const isOnline = /│ status\s+│ online\s+│/m.test(stdout); const message = isOnline ? 'Application is online and running under PM2.' : 'Application process exists but is not online.'; - res.json({ success: isOnline, message }); }); }, ); /** - * POST /geocode - * Proxies geocoding requests securely. + * POST /api/system/geocode - Geocodes a given address string. + * This acts as a secure proxy to the Google Maps Geocoding API. */ router.post( '/geocode', validateRequest(geocodeSchema), async (req: Request, res: Response, next: NextFunction) => { + // Infer type and cast request object as per ADR-003 type GeocodeRequest = z.infer; const { body: { address }, @@ -86,6 +83,7 @@ router.post( const coordinates = await geocodingService.geocodeAddress(address, req.log); if (!coordinates) { + // This check remains, but now it only fails if BOTH services fail. return res.status(404).json({ message: 'Could not geocode the provided address.' }); }