@rosepetal/node-red-contrib-async-function 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2025 Rosepetal
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,213 @@
1
+ # node-red-contrib-async-function
2
+
3
+ Run heavy computations in Node-RED without slowing down your flows. This node works like the function node you already know, but keeps things responsive when the work gets heavy.
4
+
5
+ ![Example](assets/example.png)
6
+
7
+ ## What You Get
8
+
9
+ - Write JavaScript code that feels familiar—same as the function node.
10
+ - Run CPU-intensive tasks without blocking other flows.
11
+ - See real-time stats showing active workers and queue depth.
12
+ - Configure worker pools to match your workload.
13
+ - Handle bursts of messages smoothly with automatic queuing.
14
+ - Add external npm modules with auto-installation support.
15
+
16
+ ## Before You Start
17
+
18
+ - Node.js 18 or newer (worker threads need it).
19
+ - Node-RED 2.0 or newer.
20
+
21
+ ## How It Works
22
+
23
+ Drop an **async function** node into your flow. Write your code just like you would in a regular function node. The difference? Your code runs in a separate worker thread, so heavy operations won't freeze Node-RED.
24
+
25
+ ## When to Use This
26
+
27
+ **Great For:**
28
+ - Calculating prime numbers, running crypto operations, or processing large datasets.
29
+ - Tasks that take more than 10 milliseconds to finish.
30
+ - Keeping your dashboard and other flows responsive during heavy work.
31
+
32
+ **Skip It For:**
33
+ - Simple math or quick transformations (the regular function node is faster).
34
+ - When you need `context`, `flow`, or `global` storage (coming in v2.0).
35
+
36
+ ## Node Options
37
+
38
+ ### Code & Behavior
39
+ - **Name** – Optional label for your canvas.
40
+ - **Function** – Your JavaScript code. Works with `async/await`, `return`, and `require()`.
41
+ - **Outputs** – How many output wires (0-10). Return an array for multiple outputs.
42
+ - **Timeout** – Maximum seconds to wait before killing the worker. Default: 30 seconds.
43
+
44
+ ### Worker Pool
45
+ - **Workers** – Fixed number of worker threads (1-16). Each node maintains exactly this many workers. Default: 3.
46
+ - **Queue Size** – Messages to queue when all workers are occupied. Default: 100.
47
+
48
+ ### Modules
49
+ Add external npm modules that will be available in your code. Similar to the standard Node-RED function node's module feature.
50
+
51
+ - **Module** – The npm package name (e.g., `lodash`, `moment`, `@scope/package`).
52
+ - **Import as** – Variable name to access the module in your code.
53
+
54
+ Modules are auto-installed to `~/.node-red` on first deploy if not already available. Use them directly in your code without `require()`:
55
+
56
+ ```javascript
57
+ // With modules: lodash → _, moment → moment
58
+ const doubled = _.map(msg.payload, x => x * 2);
59
+ msg.timestamp = moment().format('YYYY-MM-DD');
60
+ return msg;
61
+ ```
62
+
63
+ ### Buffer Handling
64
+ - **Buffers** – Any `Buffer` in `msg` is transferred through shared memory (`/dev/shm` on Linux, otherwise `os.tmpdir()`), with base64 fallback if needed.
65
+
66
+ ## Typical Flow
67
+
68
+ 1. Add an **async function** node to your workspace.
69
+ 2. Connect an Inject node (input) and a Debug node (output).
70
+ 3. Write a simple script:
71
+ ```javascript
72
+ msg.payload = msg.payload * 2;
73
+ return msg;
74
+ ```
75
+ 4. Deploy and trigger. Watch the status update in real time.
76
+
77
+ ## What You Can Use in Your Code
78
+
79
+ **Available:**
80
+ - `msg` – The message object (must be serializable)
81
+ - `return` – Return a single message or array of messages
82
+ - `async/await` – For asynchronous operations
83
+ - `require()` – Load Node.js built-in or installed modules
84
+ - Configured modules – Available directly as variables (no require needed)
85
+ - `console` – Logging functions
86
+ - `setTimeout`, `setInterval` – Timers
87
+
88
+ **Not Available (Yet):**
89
+ - `context`, `flow`, `global` – Coming in v2.0
90
+ - `node` – Node instance methods
91
+ - Non-serializable objects (functions, symbols, etc.)
92
+
93
+ ## Code Examples
94
+
95
+ ### Simple Transformation
96
+ ```javascript
97
+ msg.payload = msg.payload * 2;
98
+ return msg;
99
+ ```
100
+
101
+ ### Using External Modules
102
+
103
+ **Option 1: Configure in Setup tab (recommended)**
104
+
105
+ Add the module in the Modules section of the Setup tab, then use it directly:
106
+ ```javascript
107
+ // Module configured: lodash → _
108
+ msg.payload = _.sortBy(msg.payload, 'name');
109
+ return msg;
110
+ ```
111
+
112
+ **Option 2: Traditional require()**
113
+ ```javascript
114
+ const crypto = require('crypto');
115
+
116
+ msg.hash = crypto.createHash('sha256')
117
+ .update(msg.payload)
118
+ .digest('hex');
119
+
120
+ return msg;
121
+ ```
122
+
123
+ ### CPU-Intensive Task (Won't Block!)
124
+ ```javascript
125
+ function isPrime(n) {
126
+ if (n <= 1) return false;
127
+ for (let i = 2; i * i <= n; i++) {
128
+ if (n % i === 0) return false;
129
+ }
130
+ return true;
131
+ }
132
+
133
+ const limit = msg.payload;
134
+ const primes = [];
135
+
136
+ for (let i = 2; i <= limit; i++) {
137
+ if (isPrime(i)) {
138
+ primes.push(i);
139
+ }
140
+ }
141
+
142
+ msg.payload = primes;
143
+ return msg;
144
+ ```
145
+
146
+ ### Multiple Outputs
147
+ ```javascript
148
+ if (msg.payload > 100) {
149
+ return [msg, null]; // Send to first output
150
+ } else {
151
+ return [null, msg]; // Send to second output
152
+ }
153
+ ```
154
+
155
+ ## Status Display
156
+
157
+ The node shows you what's happening in real time:
158
+
159
+ - **Active: 2/4** – 2 workers processing out of 4 total
160
+ - **Queue: 5** – 5 messages waiting
161
+ - **Green dot** – Normal operation
162
+ - **Yellow dot** – Queue filling up (>50 messages)
163
+ - **Red dot** – Queue almost full (>90%) or error
164
+ - **Ring** – All workers busy with a backlog
165
+
166
+ ## Performance Notes
167
+
168
+ - Worker threads add about 5-10ms overhead per message.
169
+ - Best for operations taking more than 10ms to run.
170
+ - Each node maintains a fixed pool of workers—no startup delay or dynamic scaling overhead.
171
+ - Workers are dedicated per-node, ensuring predictable performance.
172
+ - **Binary Fast Path**: Buffers use shared memory transfer (base64 fallback), keeping messages responsive even with large payloads.
173
+ - Event loop never blocks, even when processing multi-MB binary data (images, files, etc.).
174
+
175
+ ## Error Handling
176
+
177
+ Errors in your code get caught and sent to a Catch node:
178
+
179
+ ```javascript
180
+ if (!msg.payload) {
181
+ throw new Error('Payload is required');
182
+ }
183
+ ```
184
+
185
+ ## Installation
186
+
187
+ ```bash
188
+ cd ~/.node-red
189
+ npm install @rosepetal/node-red-contrib-async-function
190
+ ```
191
+
192
+ Restart Node-RED and find the node in the **function** category.
193
+
194
+ ## Migration from Earlier Versions
195
+
196
+ If you're upgrading from a version that used `minWorkers` and `maxWorkers`:
197
+ - Your existing flows will automatically migrate to use the new `numWorkers` parameter
198
+ - The migration uses your previous `maxWorkers` value as the fixed worker count
199
+ - Check the Node-RED log for migration messages
200
+ - Edit your nodes to see the new simplified "Workers" configuration field
201
+ - **Note**: The new version uses a fixed worker pool instead of dynamic scaling for more predictable performance
202
+
203
+ ## Contributing
204
+
205
+ Found a bug or have an idea? Open an issue or pull request on [GitHub](https://github.com/rosepetal-ai/node-red-contrib-async-function).
206
+
207
+ ## License
208
+
209
+ Apache-2.0 © 2025 Rosepetal
210
+
211
+ ---
212
+
213
+ **Built by [Rosepetal](https://www.rosepetal.ai)** – Making Node-RED flows faster and friendlier.
Binary file