UNPKG

node-red-syslog

Version:

Redis stream consumer with conditional acknowledgments and resource management

273 lines (202 loc) 7.98 kB
# redis-syslog-consumer ## ⚙️ Prerequisites - **Node.js** v14 or higher - **Redis** v5.0 or higher (Streams support required) - A reachable Redis server from your environment A reusable library for consuming Redis streams reliably using consumer groups, with back‑pressure, retry, and dynamic concurrency control based on system load. Can be used as a standalone library or as a Node-RED node. --- ## 📦 Installation Add the package to your project: ```bash npm install redis-syslog-consumer ``` If using Node-RED, restart your Node-RED instance to load the new nodes. --- ## 🚀 Usage ### Standalone Usage ```javascript const { StreamProcessor, GlobalResource } = require("redis-syslog-consumer"); // Create a map to store processor instances const processors = new Map(); // Create a resource manager const resourceManager = new GlobalResource(processors, { maxConcurrency: 10, minConcurrency: 1, }); // Start the resource manager resourceManager.start(); // Message handler function const handleMessage = (message) => { console.log("Received message:", message.payload); console.log("Redis ID:", message._redisId); // Process the message... // After processing, acknowledge the message streamProcessor.acknowledgeAndDelete(message._redisId); }; // Create a stream processor const streamProcessor = new StreamProcessor( "redis://localhost:6379", "syslog", resourceManager.concurrency, handleMessage ); // Register with resource manager processors.set("syslog", streamProcessor); // Initialize the stream processor streamProcessor.initialize(); // Cleanup on shutdown process.on("SIGINT", () => { processors.delete("syslog"); resourceManager.stop(); process.exit(0); }); ``` ### Node-RED Usage Once installed, you'll have two new nodes in the palette under **Syslog** and **config**: 1. **Redis Syslog Consumer** (`redis-syslog-consumer`) 2. **Resource Manager** (`redis-syslog-resource-manager`) #### Redis Syslog Consumer Node - **Inputs**: 1 - **Outputs**: 2 (output, logs) ##### Node Properties | Property | Type | Description | | -------------------- | ------ | ------------------------------------------------ | | **Name** | String | Optional label | | **Redis URL** | String | Connection URI (`redis://host:port`) | | **Stream Key** | String | Redis stream name (e.g. `syslog`) | | **Resource Manager** | Config | Select your `redis-syslog-resource-manager` node | ##### Behavior 1. On deploy, it creates a `StreamProcessor` with: - A Redis client connection - A consumer‐group named `grp:<stream>` - A random consumer name `name:<id>` 2. **Initialization**: - Creates or reuses the Redis consumer group - Drains existing backlog (XREADGROUP from `0`) - Claims stale pending entries (older than 5 minutes) - Starts a continuous poll (BLOCK 30s) for new messages 3. **Message flow**: - Each entry becomes a Node-RED message payload (`msg.payload`) with metadata (`msg._redisId`). - The developer must re-inject an object `{ _redisId, _redisAck: true }` into the node to ACK/DEL from the stream. 4. **Logging**: any lifecycle events, errors, or debug can be emitted to the second output. #### Resource Manager Config Node Global config node that monitors CPU and RAM and adjusts all active **Redis Syslog Consumer** nodes' concurrency based on hysteresis thresholds. ##### Config Properties | Property | Default | Description | | --------------------------- | ------- | --------------------------------------- | | **Max Concurrency** | `10` | Upper bound for message‐parallelism | | **Min Concurrency** | `1` | Lower bound for parallelism | | **Sampling Size** | `10` | Number of samples in sliding window | | **Sampling Interval (ms)** | `5000` | Time between CPU/RAM checks | | **Upper CPU Threshold (%)** | `80` | CPU% above which concurrency is halved | | **Lower CPU Threshold (%)** | `30` | CPU% below which concurrency is doubled | | **Upper RAM Threshold (%)** | `80` | RAM% above which concurrency is halved | | **Lower RAM Threshold (%)** | `30` | RAM% below which concurrency is doubled | ##### Behavior - Uses `pidusage` to sample process CPU and memory. - Maintains sliding‐window averages with weighted samples. - Applies hysteresis: - **Decrease** concurrency if CPU upper CPU threshold **or** RAM upper RAM threshold. - **Increase** concurrency if both CPU < lower CPU threshold **and** RAM < lower RAM threshold. - Doubles or halves the global concurrency, clamped between min/max. --- ## 📖 API Reference ### `StreamProcessor` ```js const { StreamProcessor } = require("redis-syslog-consumer"); ``` #### Constructor ```ts new StreamProcessor( url: string, stream: string, concurrency: number, onMessageCallback: (msg: { payload: string; _redisId: string }) => void, options?: { logger?: (message: string, context?: string) => void, status?: (fill: string, shape: string, text: string) => void, consumerName?: string, consumerGroupPrefix?: string } ) ``` - **`url`**: Redis connection URI - **`stream`**: Redis stream key - **`concurrency`**: max parallel messages - **`onMessageCallback`**: invoked with each parsed message - **`options`**: Optional configuration #### Methods - `initialize(): Promise<void>` start consuming (create group, drain backlog, poll). - `acknowledgeAndDelete(messageId: string): Promise<void>` XACK + XDEL for a given message. - `setConcurrency(newConcurrency: number)` dynamically adjust concurrency. ### `GlobalResource` ```js const { GlobalResource } = require("redis-syslog-consumer"); ``` #### Constructor ```ts new GlobalResource( processors: Map<string, { setConcurrency: (number) => void }>, config?: { maxConcurrency?: number, minConcurrency?: number, samplingCount?: number, samplingIntervalMs?: number, upperCpuThresholdPercent?: number, lowerCpuThresholdPercent?: number, upperMemThresholdPercent?: number, lowerMemThresholdPercent?: number }, logger?: (message: string, context?: string) => void ) ``` #### Methods - `start()` - Start monitoring CPU and RAM usage - `stop()` - Stop monitoring - `registerProcessor(streamKey: string, processor: object)` - Add a processor - `unregisterProcessor(streamKey: string)` - Remove a processor - `get concurrency()` - Get current concurrency value --- ## 🛠 Example Node-RED Flow ```json [ { "id": "1", "type": "redis-syslog-resource-manager", "name": "ResourceManager", "concurrencyMax": 20, "concurrencyMin": 1, "samplingCount": 15, "samplingInterval": 3000, "thresholdUpper": 75, "thresholdLower": 25, "thresholdUpperMem": 75, "thresholdLowerMem": 25 }, { "id": "2", "type": "redis-syslog-consumer", "stream": "syslog", "url": "redis://127.0.0.1:6379", "resource": "1", "wires": [["3"], ["4"]] } ] ``` Inject back to acknowledge: ```json { "payload": { "redis": { "id": "1680000000000-0", "ack": true } } } ``` --- ## Contributing Contributions are welcome! Please fork the repository, create a feature branch, and submit a pull request with a detailed explanation of changes. --- ## Versioning We use [SemVer](https://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/ibs-source/syslog/tags). --- ## Authors - **Paolo Fabris** - _Initial work_ - [ibs.srl](https://www.ibs.srl/) See also the list of [contributors](https://github.com/ibs-source/syslog/blob/main/CONTRIBUTORS.md) who participated in this project. --- ## ⚖️ License This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.