Prometheus Metrics:
- Add METRICS_LABELS fallback for defaultLabels env config
- Separate includeSystem from collectDefaultMetrics with own env var
- Parse URL in /metrics endpoint to support querystrings and trailing slashes
- Sort keys in labelsToKey for stable/deterministic lookups
- Update documentation with all environment variables
Retry Utils:
- Remove abort listener on sleep completion to prevent memory leak
- Apply maxDelay cap AFTER jitter to guarantee max delay limit
- Validate/normalize attempt parameter in calculateDelay
- Count retries only when attempt > 1 (actual retry, not first try)
- Use metrics.retryExhausted instead of generic errors for exhausted retries
Tests:
- Add consistency tests to verify retryConfigs.rsocket matches constants
- Re-export RETRY_BACKOFF_DELAYS and RETRY_JITTER_FACTOR from Defaults
for backwards compatibility with existing imports
- Add 'as const' to RETRY_JITTER_FACTOR for type consistency
- Improve documentation explaining why values are hardcoded in retryConfigs
(ESM initialization order issues with indirect circular imports)
Hardcode values in retryConfigs.rsocket instead of referencing
RETRY_BACKOFF_DELAYS and RETRY_JITTER_FACTOR to avoid
"Cannot access before initialization" error in ESM module loading.
- Remove duplicate RETRY_BACKOFF_DELAYS and RETRY_JITTER_FACTOR from Defaults/index.ts
- Export constants from retry-utils.ts as single source of truth
- Add 'as const' for better type inference
- Fixes "Cannot access 'RETRY_BACKOFF_DELAYS' before initialization" error
- Add registryConfigured flag to ensure single execution of configureRegistry
- Fix race condition by moving setMetricPrefix/configureRegistry before Promise
- Remove unused prefix parameter from configureRegistry function
- Consolidate prefix to single source of truth (configuredPrefix global)
- Allow clearing default labels by passing empty object
- Add resetMetricsConfiguration() and getConfiguredPrefix() for testing
- Apply configured prefix to all metric names via getFullMetricName()
- Configure customRegistry with defaultLabels at initialization
- Prevent memory leak: collectDefaultMetrics only called once via flag
- collectDefaultMetrics now uses customRegistry instead of global
- Initialize prefix/defaultLabels before creating baileysMetrics
All metrics now properly include prefix (e.g., baileys_connection_attempts)
and inherit defaultLabels configured via environment variables.
Major improvements to prometheus-metrics.ts:
- Use custom registry instead of global promClient.register (isolation)
- Remove duplicate localValues - prom-client is now single source of truth
- Fix reset(labels) to respect labels param using remove() instead of reset()
- Migrate Summary class to use prom-client internally
- getMetricsOutput() now uses customRegistry for proper isolation
Fix misleading comments in retry-utils.ts:
- Change "exponential backoff" to "custom progressive backoff"
- Fix comment claiming constants are "from Defaults" (now local)
Breaking changes to getValues()/get() - now async as they query prom-client
Define RETRY_BACKOFF_DELAYS and RETRY_JITTER_FACTOR locally in
retry-utils.ts to avoid circular dependency that caused
"Cannot access 'RETRY_BACKOFF_DELAYS' before initialization" error.
- Add prom-client ^15.1.3 as production dependency
- Migrate Counter class to use prom-client internally
- Migrate Gauge class to use prom-client internally
- Migrate Histogram class to use prom-client internally
- Update getMetricsOutput() to use prom-client's native metrics()
- Update contentType() to use prom-client's contentType
- Enable collectDefaultMetrics() for Node.js system metrics
- Maintain backward compatibility with existing API
Benefits:
- Native OpenMetrics format export
- Proper histogram bucket handling
- Default Node.js metrics (memory, CPU, event loop, GC)
- Better integration with Grafana/Prometheus ecosystem
- Integrate RETRY_BACKOFF_DELAYS and RETRY_JITTER_FACTOR into retry-utils.ts
- Add retryConfigs.rsocket using the default delays
- Add getRetryDelayWithJitter() helper function
- Add getAllRetryDelaysWithJitter() for planning
- Document DEFAULT_CACHE_MAX_KEYS with usage example
- Adjust INITIAL_PREKEY_COUNT from 30 to 200 (moderate value)
- Adjust MIN_UPLOAD_INTERVAL from 60s to 10s (balance rate limiting/responsiveness)
- Revert syncFullHistory to true (avoid breaking change)
- Integrate RETRY_BACKOFF_DELAYS and RETRY_JITTER_FACTOR into retry-utils.ts
- Add retryConfigs.rsocket using the default delays
- Add getRetryDelayWithJitter() helper function
- Add getAllRetryDelaysWithJitter() for planning
- Document DEFAULT_CACHE_MAX_KEYS with usage example
- Adjust INITIAL_PREKEY_COUNT from 30 to 200 (moderate value)
- Adjust MIN_UPLOAD_INTERVAL from 60s to 10s (balance rate limiting/responsiveness)
- Revert syncFullHistory to true (avoid breaking change)
FIX: startPromise was never cleared after stop(), causing start()
to return the old resolved promise instead of creating a new server.
This broke any flow that stops and restarts metrics (config reloads, tests).
Now stop() clears startPromise, allowing proper server restart.
Fixes based on Copilot AI and Codex code review comments:
1. Race Condition Fix (lines 1065-1069):
- BEFORE: setTimeout(100ms) was incomplete - callers could resolve
before server was actually ready
- FIX: Cache the Promise from first start() call using startPromise
- All concurrent calls now return the same Promise
- Properly handles both success and error cases
2. CPU Percentage Calculation (lines 993-996):
- BEFORE: Division by cpuCount gave artificially low values
(e.g., 25% instead of 100% on 4-core for single-threaded process)
- FIX: Removed cpuCount division
- Now follows Unix/Prometheus standard: 100% = 1 core fully used
- Values can exceed 100% on multi-core (200% = 2 cores at 100%)
- Updated metric description to clarify this behavior
Fixes based on Copilot AI and Codex code review comments:
1. CPU Usage Metric (line ~930-933):
- FIX: process.cpuUsage() now calculates delta between measurements
- Returns actual percentage (0-100) instead of cumulative seconds
- Normalized across CPU cores
2. Duplicate SystemMetricsCollector (line ~1353-1355):
- FIX: Removed duplicate instantiation from PrometheusMetricsManager
- Now uses MetricsServer's collector via getSystemCollector()
3. Collection Interval (line ~1006-1008):
- FIX: Added collectIntervalMs to MetricsConfig
- Configurable via BAILEYS_PROMETHEUS_COLLECT_INTERVAL_MS
4. Error Handling (line ~1021-1022):
- FIX: Enhanced error messages with structured JSON response
- Includes error message, timestamp, and logs to console
5. Server Binding Security (line ~1034-1038):
- FIX: Default host changed from 0.0.0.0 to 127.0.0.1
- Configurable via BAILEYS_PROMETHEUS_HOST
- Warning shown if exposed on all interfaces
6. Race Condition (line ~998-1001):
- FIX: Added isStarting flag to prevent concurrent initialization
- Multiple concurrent start() calls now handled safely
- Support BAILEYS_PROMETHEUS_ENABLED, BAILEYS_PROMETHEUS_PORT, etc.
- Add support for BAILEYS_PROMETHEUS_LABELS JSON configuration
- Maintain backward compatibility with METRICS_* prefix
- Update default port to 9092 (matching user's .env)
- Enable by opt-in (enabled=false by default)
- Improved startup log with labels info
- baileys-event-stream.ts: Add null check for buffer item in priority insertion
- baileys-logger.ts: Handle 'silent' log level and fix JID sanitization
- cache-utils.ts: Fix type incompatibility in global cache with any type
- logger-adapter.ts: Add nullish coalescing for level mapping and fix console type cast
- prometheus-metrics.ts: Rename private 'metrics' property to 'metricsMap' to avoid conflict with method
- trace-context.ts: Store baggage header in variable before accessing to fix undefined check
- Translate all Portuguese comments to English in utility modules
- Enhance circuit-breaker.ts with sliding window failure tracking
- Add factory functions for WhatsApp-specific circuit breakers
(createPreKeyCircuitBreaker, createConnectionCircuitBreaker, createMessageCircuitBreaker)
- Improve volume threshold support for circuit breaker decisions
- Standardize documentation across all utility files
Files updated:
- structured-logger.ts: English comments
- baileys-logger.ts: English comments
- trace-context.ts: English comments
- prometheus-metrics.ts: English comments
- cache-utils.ts: English comments
- circuit-breaker.ts: Enhanced with sliding window + English comments
- retry-utils.ts: English comments
- baileys-event-stream.ts: English comments
- index.ts: English comments
* fix: improve message resend logic by adding checks for message IDs
* Revert "fix: improve message resend logic by adding checks for message IDs"
This reverts commit c03f9d8e6fc6cbfbb9d1f8f67c169700e704213d.
* feat: add group member label update functionality and event emission
* feat: refactor updateMemberLabel function for improved readability
* feat: use optional chaining for label association message in processMessage
* feat: add updateMemberLabel to makeMessagesSocket for enhanced functionality
* fix: correct log message for group member tag update event
Co-authored-by: FgsiDev
* Memory leak in makeMutex - Promise never gets garbage collected
Hey, I've been debugging a memory leak in my application and traced it back to the makeMutex implementation.
The current implementation chains promises indefinitely without ever breaking the chain:
Every call to mutex() creates a new Promise that awaits the previous task, then becomes the new task. The problem is the old promises never get released because each one holds a reference to the previous through the closure.
What I found
Took a heap snapshot after running for a while and found hundreds of Promises from make-mutex.js holding ~15MB and growing. The retainer graph shows a long chain of Promises all pointing back to each other.
Since processingMutex handles every incoming message/notification, this chain grows constantly and never shrinks.
This keeps the same mutex behavior but lets the GC clean up old promises every 50 tasks instead of holding them forever.
* Refactor makeMutex to use AsyncMutex directly
* lint
* revert