diff --git a/apps/webapp/app/env.server.ts b/apps/webapp/app/env.server.ts index 1cc0db0bf0..095abd45ca 100644 --- a/apps/webapp/app/env.server.ts +++ b/apps/webapp/app/env.server.ts @@ -1260,6 +1260,7 @@ const EnvironmentSchema = z EVENT_LOOP_MONITOR_THRESHOLD_MS: z.coerce.number().int().default(100), EVENT_LOOP_MONITOR_UTILIZATION_INTERVAL_MS: z.coerce.number().int().default(1000), EVENT_LOOP_MONITOR_UTILIZATION_SAMPLE_RATE: z.coerce.number().default(0.05), + EVENT_LOOP_MONITOR_NOTIFY_ENABLED: z.string().default("0"), VERY_SLOW_QUERY_THRESHOLD_MS: z.coerce.number().int().optional(), diff --git a/apps/webapp/app/eventLoopMonitor.server.ts b/apps/webapp/app/eventLoopMonitor.server.ts index b86ea3d31a..0a1b33690b 100644 --- a/apps/webapp/app/eventLoopMonitor.server.ts +++ b/apps/webapp/app/eventLoopMonitor.server.ts @@ -9,6 +9,23 @@ import { signalsEmitter } from "./services/signals.server"; const THRESHOLD_NS = env.EVENT_LOOP_MONITOR_THRESHOLD_MS * 1e6; +// ANSI color codes for terminal output +const RED = "\x1b[31m"; +const YELLOW = "\x1b[33m"; +const RESET = "\x1b[0m"; + +function notifyEventLoopBlocked(timeMs: number, asyncType: string): void { + if (env.EVENT_LOOP_MONITOR_NOTIFY_ENABLED !== "1") { + return; + } + + console.warn( + `${RED}⚠️ Event loop blocked${RESET} for ${YELLOW}${timeMs.toFixed( + 1 + )}ms${RESET} (${asyncType})` + ); +} + const cache = new Map(); function init(asyncId: number, type: string, triggerAsyncId: number, resource: any) { @@ -66,6 +83,8 @@ function after(asyncId: number) { ); newSpan.end(); + + notifyEventLoopBlocked(time, cached.type); } }