@stephen-shopopop/node-metrics
    Preparing search index...

    @stephen-shopopop/node-metrics

    node-metrics

    npm version License: ISC Node.js

    πŸš€ Process load measuring plugin for Node.js with automatic "Service Unavailable" handling

    A lightweight, production-ready middleware for monitoring Node.js application health and automatically handling server overload situations. Integrates seamlessly with popular frameworks (Koa, Express, Hono) and provides Prometheus-compatible metrics.

    • 🎯 Automatic Overload Protection - Returns HTTP 503 when system is under pressure
    • πŸ“Š Real-time Metrics - Monitor event loop delay, heap usage, RSS, and event loop utilization
    • πŸ”Œ Framework Support - Works with Koa, Express, Hono, and vanilla Node.js
    • πŸ“ˆ Prometheus Integration - Built-in metrics endpoint and dashboard
    • ⚑ Low Overhead - Uses setTimeout instead of setInterval to minimize system pressure
    • 🎨 Web Dashboard - Beautiful UI to visualize metrics in real-time
    npm install @stephen-shopopop/node-metrics
    
    const Koa = require('koa');
    const { underPressureKoaMiddleware } = require('@stephen-shopopop/node-metrics');

    const app = new Koa();

    app.use(underPressureKoaMiddleware({
    appName: 'service-order',
    maxEventLoopDelay: 1000,
    maxHeapUsedBytes: 100000000,
    maxRssBytes: 100000000,
    maxEventLoopUtilization: 0.98,
    retryAfter: 10,
    webServerMetricsPort: 9090
    }));

    app.use(async ctx => {
    ctx.body = 'Hello World';
    });

    app.listen(3000);
    const express = require('express');
    const { underPressureExpressMiddleware } = require('@stephen-shopopop/node-metrics');

    const app = express();
    const port = 3000;

    app.use(underPressureExpressMiddleware({
    appName: 'service-order',
    maxEventLoopDelay: 1000,
    maxHeapUsedBytes: 100000000,
    maxRssBytes: 100000000,
    maxEventLoopUtilization: 0.98,
    retryAfter: 10,
    webServerMetricsPort: 9090
    }));

    app.get('/', (req, res) => {
    res.send('Hello World!');
    });

    app.listen(port, () => {
    console.log(`Example app listening on port ${port}`);
    });
    import { Hono } from 'hono';
    import { underPressureHonoMiddleware } from '@stephen-shopopop/node-metrics';

    const app = new Hono();

    app.use('*', underPressureHonoMiddleware({
    appName: 'service-order',
    maxEventLoopDelay: 1000,
    maxHeapUsedBytes: 100000000,
    maxRssBytes: 100000000,
    maxEventLoopUtilization: 0.98,
    retryAfter: 10,
    webServerMetricsPort: 9090
    }));

    app.get('/', (c) => c.text('Hello Hono!'));

    export default app;
    import { createServer } from 'node:http';
    import { Metrics, isUnderPressure } from '@stephen-shopopop/node-metrics';

    const metrics = Metrics.start({
    appName: 'service-order',
    sampleIntervalInMs: 1000,
    resolution: 10,
    webServerMetricsPort: 9090
    });

    const options = {
    maxEventLoopDelay: 1000,
    maxHeapUsedBytes: 100000000,
    maxRssBytes: 100000000,
    maxEventLoopUtilization: 0.98
    };

    const hostname = '127.0.0.1';
    const port = 3000;

    const server = createServer((req, res) => {
    if (isUnderPressure({ ...options, ...metrics.measures() })) {
    res.statusCode = 503;
    res.setHeader('Retry-After', '10');
    res.end('Service Unavailable');
    return;
    }

    res.statusCode = 200;
    res.setHeader('Content-Type', 'text/plain');
    res.end('Hello World');
    });

    server.listen(port, hostname, () => {
    console.log(`Server running at http://${hostname}:${port}/`);
    });

    You can set up metrics separately and preload them when starting your application:

    // file: metrics.js
    import { Metrics } from '@stephen-shopopop/node-metrics';

    const metrics = Metrics.start({
    webServerMetricsPort: 9090,
    appName: 'service-test'
    });

    process.on('SIGTERM', () => {
    metrics
    .closeWebServerMetrics()
    .then(() => console.log('Metrics terminated'))
    .catch((error) => console.error('Error terminating metrics', error))
    .finally(() => process.exit(0));
    });

    Run your application with metrics preloaded:

    node -r ./metrics.js app.js
    
    Option Type Default Description
    appName string - Required. Application name (format: service-name)
    sampleIntervalInMs number 1000 Interval in milliseconds for metrics collection
    resolution number 10 Resolution/granularity of collected metrics
    webServerMetricsPort number - Port for Prometheus metrics server (recommended: 9090)
    maxEventLoopDelay number - Maximum allowed event loop delay (ms)
    maxEventLoopUtilization number - Maximum event loop utilization (0-1, e.g., 0.98 = 98%)
    maxHeapUsedBytes number - Maximum heap memory usage in bytes
    maxRssBytes number - Maximum Resident Set Size in bytes
    retryAfter number - Seconds to wait before retrying (sent in Retry-After header)
    {
    appName: 'service-order',
    sampleIntervalInMs: 1000, // Collect metrics every second
    resolution: 10, // Keep last 10 samples
    maxEventLoopDelay: 1000, // Alert if event loop delay > 1000ms
    maxEventLoopUtilization: 0.98, // Alert if event loop > 98% utilized
    maxHeapUsedBytes: 100000000, // Alert if heap > 100MB
    maxRssBytes: 100000000, // Alert if RSS > 100MB
    retryAfter: 10, // Tell clients to retry after 10s
    webServerMetricsPort: 9090 // Serve metrics on port 9090
    }

    Access the beautiful real-time dashboard at:

    http://127.0.0.1:9090
    

    Dashboard UI

    Metrics are exposed in Prometheus format at:

    http://127.0.0.1:9090/metrics
    

    Available Metrics:

    # HELP nodejs_event_loop_delay_milliseconds The mean of the recorded event loop delays
    # TYPE nodejs_event_loop_delay_milliseconds gauge
    nodejs_event_loop_delay_milliseconds{service="service-order"} 0.9878575824175826
    
    # HELP nodejs_event_loop_utilized The percentage of event loop utilization
    # TYPE nodejs_event_loop_utilized gauge
    nodejs_event_loop_utilized{service="service-order"} 0.10445105761836926
    
    # HELP nodejs_heap_used_bytes The amount of memory used by the V8 heap
    # TYPE nodejs_heap_used_bytes gauge
    nodejs_heap_used_bytes{service="service-order"} 32637488
    
    # HELP nodejs_heap_total_bytes The total size of the V8 heap
    # TYPE nodejs_heap_total_bytes gauge
    nodejs_heap_total_bytes{service="service-order"} 34684928
    
    # HELP nodejs_rss_bytes The resident set size, or total memory allocated for the process
    # TYPE nodejs_rss_bytes gauge
    nodejs_rss_bytes{service="service-order"} 179077120
    
    # HELP nodejs_process_start_time_seconds The process start time, represented in seconds since the Unix epoch
    # TYPE nodejs_process_start_time_seconds gauge
    nodejs_process_start_time_seconds{service="service-order"} 1750345329
    
    # HELP nodejs_process_cpu_user_seconds_total The total user CPU time consumed by the process, in seconds
    # TYPE nodejs_process_cpu_user_seconds_total counter
    nodejs_process_cpu_user_seconds_total{service="service-order"} 1.494779
    
    # HELP nodejs_process_cpu_system_seconds_total The total system CPU time consumed by the process, in seconds
    # TYPE nodejs_process_cpu_system_seconds_total counter
    nodejs_process_cpu_system_seconds_total{service="service-order"} 0.120983
    
    # HELP nodejs_process_cpu_seconds_total The total CPU time (user + system) consumed by the process, in seconds
    # TYPE nodejs_process_cpu_seconds_total counter
    nodejs_process_cpu_seconds_total{service="service-order"} 1.615762
    
    # HELP nodejs_active_handles Number of active libuv handles grouped by handle type
    # TYPE nodejs_active_handles gauge
    nodejs_active_handles{service="service-order",type="WriteStream"} 2
    nodejs_active_handles{service="service-order",type="ReadStream"} 1
    nodejs_active_handles{service="service-order",type="Server"} 1
    nodejs_active_handles{service="service-order",type="Socket"} 1
    

    Under the hood, node-metrics uses setTimeout to perform polling checks instead of setInterval. This design choice is intentional to avoid adding additional pressure to an already stressed system.

    Why setTimeout?

    • setInterval calls repeatedly at scheduled intervals regardless of whether the previous call completed, potentially piling up calls when the server is under load
    • setTimeout is called only once and reschedules itself after completion, preventing call accumulation
    • This ensures the monitoring itself doesn't contribute to system overload

    Note: The two methods are not identical in behavior. The timer function is not guaranteed to run at the exact same rate when the system is under pressure or running long processes, but this trade-off is acceptable for health monitoring purposes.

    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚ APPLICATION LAYER β”‚
    β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
    β”‚ β”‚ Koa β”‚ β”‚ Express β”‚ β”‚ Hono β”‚ β”‚
    β”‚ β”‚ Application β”‚ β”‚ Application β”‚ β”‚ Application β”‚ β”‚
    β”‚ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
    β”‚ β”‚ β”‚ β”‚ β”‚
    β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
    β”‚ β”‚ β”‚
    β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
    β”‚ β”‚ Middleware Integration β”‚ β”‚
    β”‚ β”‚ underPressure*Middleware() β”‚ β”‚
    β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    β”‚
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚ CORE LAYER β”‚
    β”‚ β”‚
    β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
    β”‚ β”‚ Metrics (Singleton) β”‚ β”‚
    β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚
    β”‚ β”‚ β”‚ start() β”‚ register() β”‚ measures() β”‚ destroy()β”‚ β”‚ β”‚
    β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
    β”‚ β”‚ β”‚ β”‚
    β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚
    β”‚ β”‚ β”‚ Timer │──────▢│ Mediator β”‚ β”‚ β”‚
    β”‚ β”‚ β”‚(setTimeout) β”‚ β”‚ (Plugins) β”‚ β”‚ β”‚
    β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
    β”‚ β”‚ β”‚ β”‚ β”‚
    β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚
    β”‚ β”‚ β”‚ StoreBuilder (Metrics Storage) β”‚ β”‚ β”‚
    β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
    β”‚ β”‚ β”‚ β”‚ β”‚
    β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚
    β”‚ β”‚ β”‚ BroadcastChannel (Pub/Sub) β”‚ β”‚ β”‚
    β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
    β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
    β”‚ β”‚ β”‚
    β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
    β”‚ β”‚ Metrics Server β”‚ β”‚
    β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚
    β”‚ β”‚ β”‚ GET / β”‚ β”‚ GET /metrics β”‚ β”‚ GET /metrics-stream β”‚ β”‚ β”‚
    β”‚ β”‚ β”‚ Dashboard β”‚ β”‚ Prometheus β”‚ β”‚ SSE Stream β”‚ β”‚ β”‚
    β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
    β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    β”‚
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚ PLUGIN LAYER β”‚
    β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
    β”‚ β”‚ Memory β”‚ β”‚ Event Loop β”‚ β”‚ Event Loop β”‚ β”‚
    β”‚ β”‚ Usage β”‚ β”‚ Delay β”‚ β”‚ Utilization β”‚ β”‚
    β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
    β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
    β”‚ β”‚ Process CPU β”‚ β”‚ Process β”‚ β”‚ Active Handles/ β”‚ β”‚
    β”‚ β”‚ Usage β”‚ β”‚ Uptime β”‚ β”‚ Resources β”‚ β”‚
    β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜


    πŸ“Š Request Flow with Pressure Detection:

    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚ HTTP β”‚
    β”‚ Request β”‚
    β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
    β”‚
    β–Ό
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚ Middleware β”‚
    β”‚ Check β”‚
    β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    β”‚
    β–Ό
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚ measures() β”‚
    β”‚ Get current β”‚
    β”‚ metrics β”‚
    β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    β”‚
    β–Ό
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚ isUnderPressure() β”‚
    β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
    β”‚ β”‚ Event Loop Delay > max?β”‚ β”‚
    β”‚ β”‚ Heap Usage > max? β”‚ β”‚
    β”‚ β”‚ RSS Memory > max? β”‚ β”‚
    β”‚ β”‚ EL Utilization > max? β”‚ β”‚
    β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
    β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    β”‚ β”‚
    Yes β”‚ β”‚ No
    β–Ό β–Ό
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚ Return 503 β”‚ β”‚ Continue to β”‚
    β”‚ Service β”‚ β”‚ next() β”‚
    β”‚ Unavailableβ”‚ β”‚ β”‚
    β”‚ Retry-Afterβ”‚ β”‚ β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜


    ⏱️ Periodic Metrics Collection (Every sampleIntervalInMs):

    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚ setTimeout β”‚
    β”‚ Trigger β”‚
    β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
    β”‚
    β–Ό
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚ Mediator β”‚
    β”‚ Iterate Plugins β”‚
    β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    β”‚
    β–Ό
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚ Each Plugin.capture(StoreBuilder) β”‚
    β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
    β”‚ β”‚ MemoryUsagePlugin β”‚ β”‚
    β”‚ β”‚ β†’ heap_used_bytes β”‚ β”‚
    β”‚ β”‚ β†’ rss_bytes β”‚ β”‚
    β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚
    β”‚ β”‚ EventLoopDelayPlugin β”‚ β”‚
    β”‚ β”‚ β†’ event_loop_delay_milliseconds β”‚ β”‚
    β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚
    β”‚ β”‚ EventLoopUtilizationPlugin β”‚ β”‚
    β”‚ β”‚ β†’ event_loop_utilized β”‚ β”‚
    β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚
    β”‚ β”‚ ProcessCpuUsagePlugin β”‚ β”‚
    β”‚ β”‚ β†’ process_cpu_*_seconds_total β”‚ β”‚
    β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
    β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    β”‚
    β–Ό
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚ StoreBuilder β”‚
    β”‚ Update Metrics β”‚
    β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    β”‚
    β–Ό
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚ BroadcastChannel β”‚
    β”‚ Publish Update β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    β”‚
    β–Ό
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚ Subscribers (Dashboard, β”‚
    β”‚ Metrics Stream, etc.) β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

    For detailed API documentation and advanced usage:

    Contributions are welcome! Please feel free to submit a Pull Request.

    ISC Β© Stephen Deletang


    Made with ❀️ by Stephen Deletang