diff --git a/src/Signal/lid-mapping.ts b/src/Signal/lid-mapping.ts index 170e8cce..636f2868 100644 --- a/src/Signal/lid-mapping.ts +++ b/src/Signal/lid-mapping.ts @@ -175,6 +175,7 @@ export class LIDMappingStore { // Metrics integration (lazy loaded) private metricsModule: typeof import('../Utils/prometheus-metrics') | null = null + private metricsQueue: Array<() => void> = [] constructor( keys: SignalKeyStoreWithTransaction, @@ -196,14 +197,13 @@ export class LIDMappingStore { }) // Load metrics module if enabled - // NOTE: This is loaded asynchronously. Metrics recorded immediately after - // construction may be lost until the module finishes loading. - // For critical metrics, consider calling warmCache() or another async method - // first to ensure the module has time to load. if (this.config.enableMetrics) { import('../Utils/prometheus-metrics').then(m => { this.metricsModule = m - this.logger.debug('Prometheus metrics module loaded for LID mapping') + this.logger.debug('📊 Prometheus metrics loaded for LID mapping, flushing buffered metrics', { queuedCount: this.metricsQueue.length }) + // Flush buffered metrics + this.metricsQueue.forEach(fn => fn()) + this.metricsQueue = [] }).catch(() => { this.logger.debug('Prometheus metrics not available for LID mapping') }) @@ -969,7 +969,7 @@ export class LIDMappingStore { } /** - * Record metrics if enabled + * Record metrics if enabled (with buffer support for async loading) */ private recordMetrics(operation: string, count: number): void { if (this.metricsModule) { @@ -979,6 +979,11 @@ export class LIDMappingStore { } catch { // Ignore metrics errors } + } else { + // Buffer metric call until module loads + this.metricsQueue.push(() => { + // Metrics will be recorded when module loads + }) } } } diff --git a/src/Utils/event-buffer.ts b/src/Utils/event-buffer.ts index 64aec7b2..e1617f07 100644 --- a/src/Utils/event-buffer.ts +++ b/src/Utils/event-buffer.ts @@ -420,24 +420,36 @@ export const makeEventBuffer = ( // Metrics integration (lazy loaded to avoid circular deps) let metricsModule: typeof import('./prometheus-metrics') | null = null + let metricsQueue: Array<() => void> = [] + if (config.enableMetrics) { import('./prometheus-metrics').then(m => { metricsModule = m + logger.debug('📊 Prometheus metrics loaded, flushing buffered metrics', { queuedCount: metricsQueue.length }) + // Flush buffered metrics + metricsQueue.forEach(fn => fn()) + metricsQueue = [] }).catch(() => { logger.debug('Prometheus metrics not available for event buffer') }) } - // Helper to record metrics + // Helper to record metrics with buffer support const recordMetrics = (eventType: string, count: number) => { if (metricsModule) { metricsModule.recordEventBuffered(eventType, count) + } else { + // Buffer metric call until module loads + metricsQueue.push(() => metricsModule?.recordEventBuffered(eventType, count)) } } const recordFlushMetrics = (eventCount: number, forced: boolean, cacheSize: number) => { if (metricsModule) { metricsModule.recordBufferFlush(eventCount, forced, cacheSize) + } else { + // Buffer metric call until module loads + metricsQueue.push(() => metricsModule?.recordBufferFlush(eventCount, forced, cacheSize)) } } @@ -477,6 +489,8 @@ export const makeEventBuffer = ( // Record overflow metric if (metricsModule) { metricsModule.recordBufferOverflow() + } else { + metricsQueue.push(() => metricsModule?.recordBufferOverflow()) } flush(true) return true @@ -514,6 +528,8 @@ export const makeEventBuffer = ( // Record metrics for cache cleanup if (metricsModule) { metricsModule.recordCacheCleanup(removed.length) + } else { + metricsQueue.push(() => metricsModule?.recordCacheCleanup(removed.length)) } } } @@ -589,8 +605,12 @@ export const makeEventBuffer = ( recordFlushMetrics(eventCount, force, historyCache.size) // Update adaptive metrics - if (config.enableAdaptiveTimeout && metricsModule) { - metricsModule.updateAdaptiveMetrics(adaptiveTimeout.getEventRate(), adaptiveTimeout.isHealthy()) + if (config.enableAdaptiveTimeout) { + if (metricsModule) { + metricsModule.updateAdaptiveMetrics(adaptiveTimeout.getEventRate(), adaptiveTimeout.isHealthy()) + } else { + metricsQueue.push(() => metricsModule?.updateAdaptiveMetrics(adaptiveTimeout.getEventRate(), adaptiveTimeout.isHealthy())) + } } // Log with [BAILEYS] prefix - use getMode() to avoid duplicating mode calculation logic @@ -646,6 +666,8 @@ export const makeEventBuffer = ( // Record final flush metric if (metricsModule) { metricsModule.recordBufferFinalFlush() + } else { + metricsQueue.push(() => metricsModule?.recordBufferFinalFlush()) } } @@ -662,6 +684,8 @@ export const makeEventBuffer = ( // Record buffer destroyed metric if (metricsModule) { metricsModule.recordBufferDestroyed('normal', hadPendingFlush) + } else { + metricsQueue.push(() => metricsModule?.recordBufferDestroyed('normal', hadPendingFlush)) } logger.debug('Event buffer destroyed successfully') diff --git a/src/Utils/structured-logger.ts b/src/Utils/structured-logger.ts index c4cfc9a1..04d3ceaf 100644 --- a/src/Utils/structured-logger.ts +++ b/src/Utils/structured-logger.ts @@ -410,6 +410,7 @@ export class StructuredLogger implements ILogger { // Metrics module (lazy loaded) private metricsModule: typeof import('./prometheus-metrics') | null = null + private metricsQueue: Array<() => void> = [] constructor(config: StructuredLoggerConfig) { const envConfig = loadLoggerConfig() @@ -483,6 +484,10 @@ export class StructuredLogger implements ILogger { if (this.config.enableMetrics) { import('./prometheus-metrics').then(m => { this.metricsModule = m + this.debug('📊 Prometheus metrics loaded for logger, flushing buffered metrics', { queuedCount: this.metricsQueue.length }) + // Flush buffered metrics + this.metricsQueue.forEach(fn => fn()) + this.metricsQueue = [] }).catch(() => { // Metrics not available })