node-red-contrib-qrusty 0.19.19 → 0.20.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/README.md CHANGED
@@ -1,28 +1,135 @@
1
1
  # node-red-contrib-qrusty
2
2
 
3
- Node-RED Function node snippets for interacting with a Qrusty server.
4
-
5
- ## Notes
6
-
7
- - Default server URL in examples assumes Docker Compose service name `queue-server` on port `6784`.
8
- - Qrusty expects `payload` to be a JSON string for `POST /publish`, so the publish snippet uses `JSON.stringify(msg.payload)`.
9
-
10
- ## Included snippets
11
-
12
- - `qrusty-publish.js` (POST `/publish`)
13
- - `qrusty-consume.js` (POST `/consume/{queue}`)
14
- - `qrusty-ack.js` (POST `/ack/{queue}/{id}`)
15
- - `qrusty-nack.js` (POST `/nack/{queue}/{id}`)
16
- - `qrusty-create-queue.js` (POST `/create-queue`)
17
- - `qrusty-update-queue.js` (POST `/update-queue`)
18
- - `qrusty-delete-queue.js` (DELETE `/delete-queue/{queue}`)
19
- - `qrusty-purge-queue.js` (POST `/purge-queue/{queue}`)
20
- - `qrusty-stats.js` (GET `/stats`)
21
- - `qrusty-queue-stats.js` (GET `/queue-stats/{queue}`)
22
- - `qrusty-queue-metrics.js` (GET `/queues/{queue}/metrics`)
23
- - `qrusty-list-queues.js` (GET `/queues`)
24
- - `qrusty-purge-all.js` (POST `/purge-all`)
25
- - `qrusty-delete-all.js` (POST `/delete-all`)
26
- - `qrusty-ack-batch.js` (POST `/ack-batch/{queue}`)
27
- - `qrusty-nack-batch.js` (POST `/nack-batch/{queue}`)
28
- - `qrusty-health.js` (GET `/health`)
3
+ Node-RED custom nodes for the [Qrusty](https://github.com/greeng3/qrusty)
4
+ priority queue server.
5
+
6
+ Wraps the [`qrusty-client`](https://www.npmjs.com/package/qrusty-client)
7
+ Node.js client in fully-typed, HTML-templated Node-RED nodes so you can
8
+ drag-and-drop queue operations into your flows instead of hand-rolling
9
+ `function` nodes.
10
+
11
+ ## Install
12
+
13
+ From the Node-RED palette manager, search for `node-red-contrib-qrusty`
14
+ and install. Or from the command line in your Node-RED user directory
15
+ (typically `~/.node-red`):
16
+
17
+ ```bash
18
+ npm install node-red-contrib-qrusty
19
+ ```
20
+
21
+ Requires Node.js 18 or newer and Node-RED 3.0 or newer.
22
+
23
+ ## Nodes
24
+
25
+ One config node plus 17 action nodes. All action nodes reference a
26
+ shared `qrusty-server` config node so you only enter the host/port once
27
+ per environment.
28
+
29
+ ### Config node
30
+
31
+ | Node | Purpose |
32
+ | --------------- | ----------------------------------------------------------------------------------------------- |
33
+ | `qrusty-server` | Holds host, port, and `useHttps` for a Qrusty server. Computes `baseUrl = http(s)://host:port`. |
34
+
35
+ ### Message operations
36
+
37
+ | Node | HTTP endpoint | Purpose |
38
+ | ------------------- | ------------------------- | -------------------------------------- |
39
+ | `qrusty-publish` | `POST /publish` | Publish `msg.payload` to a queue. |
40
+ | `qrusty-consume` | `POST /consume/:queue` | Pop one message (or null). |
41
+ | `qrusty-ack` | `POST /ack/:queue/:id` | Acknowledge a message. |
42
+ | `qrusty-nack` | `POST /nack/:queue/:id` | Negatively acknowledge (retry or DLQ). |
43
+ | `qrusty-ack-batch` | `POST /ack-batch/:queue` | Ack many ids in one request. |
44
+ | `qrusty-nack-batch` | `POST /nack-batch/:queue` | Nack many ids in one request. |
45
+
46
+ ### Queue management
47
+
48
+ | Node | HTTP endpoint | Purpose |
49
+ | --------------------- | ----------------------------- | ------------------------------------------------ |
50
+ | `qrusty-create-queue` | `POST /create-queue` | Create a queue with ordering / duplicate policy. |
51
+ | `qrusty-update-queue` | `POST /update-queue` | Rename or toggle duplicate protection. |
52
+ | `qrusty-delete-queue` | `DELETE /delete-queue/:queue` | Delete a queue and its messages. |
53
+ | `qrusty-purge-queue` | `POST /purge-queue/:queue` | Empty a queue without deleting it. |
54
+ | `qrusty-purge-all` | `POST /purge-all` | Empty every queue. |
55
+ | `qrusty-delete-all` | `POST /delete-all` | Delete every queue. |
56
+
57
+ ### Observability
58
+
59
+ | Node | HTTP endpoint | Purpose |
60
+ | ---------------------- | ---------------------------- | -------------------------------- |
61
+ | `qrusty-stats` | `GET /stats` | Aggregate stats for every queue. |
62
+ | `qrusty-queue-stats` | `GET /queue-stats/:queue` | Detailed stats for one queue. |
63
+ | `qrusty-queue-metrics` | `GET /queues/:queue/metrics` | Per-second time-series metrics. |
64
+ | `qrusty-list-queues` | `GET /queues` | Names of all existing queues. |
65
+ | `qrusty-health` | `GET /health` | Server health check. |
66
+
67
+ ## Config-vs-msg fallback
68
+
69
+ Every action node supports two ways of supplying its parameters:
70
+
71
+ 1. **In the editor panel** — values set on the node itself (e.g. a hard-coded
72
+ `queue` field) take precedence.
73
+ 2. **At runtime via the incoming `msg`** — leave the field blank on the node
74
+ and supply `msg.queue`, `msg.priority`, etc.
75
+
76
+ This lets you build generic flows (`msg.queue` decided upstream) or
77
+ explicit flows (queue pinned in the editor), or a mix of both.
78
+
79
+ ## Error handling
80
+
81
+ - A green status dot with `"ok"` means the HTTP call succeeded.
82
+ - A blue dot with `"requesting"` shows the call is in flight.
83
+ - A red ring with `"HTTP 4xx"` / `"HTTP 5xx"` / `"no server config"` means
84
+ the node failed; the error is forwarded via `done(err)` so a downstream
85
+ `catch` node will pick it up.
86
+
87
+ ## Example flow
88
+
89
+ ```json
90
+ [
91
+ {
92
+ "id": "srv",
93
+ "type": "qrusty-server",
94
+ "name": "dev",
95
+ "host": "localhost",
96
+ "port": "6784",
97
+ "useHttps": false
98
+ },
99
+ {
100
+ "id": "inject",
101
+ "type": "inject",
102
+ "payload": "hello from node-red",
103
+ "payloadType": "str",
104
+ "wires": [["pub"]]
105
+ },
106
+ {
107
+ "id": "pub",
108
+ "type": "qrusty-publish",
109
+ "name": "",
110
+ "server": "srv",
111
+ "queue": "orders",
112
+ "priority": "10",
113
+ "wires": [[]]
114
+ }
115
+ ]
116
+ ```
117
+
118
+ ## Development
119
+
120
+ ```bash
121
+ cd integrations/node-red
122
+ npm install
123
+ npm test # runs mocha against node-red-node-test-helper
124
+ ```
125
+
126
+ The test suite in `test/` uses the official
127
+ [`node-red-node-test-helper`](https://www.npmjs.com/package/node-red-node-test-helper)
128
+ to load every node into a real Node-RED runtime and exercise it end-to-end
129
+ against a mocked HTTP server.
130
+
131
+ ## Versioning
132
+
133
+ This package tracks the Qrusty server version. When the server bumps
134
+ (e.g. `0.19.x`), this package is bumped in lockstep and its
135
+ `qrusty-client` dependency is pinned to the matching major.minor.
package/lib/common.js ADDED
@@ -0,0 +1,94 @@
1
+ // lib/common.js
2
+ //
3
+ // Shared helpers for all Qrusty Node-RED action nodes.
4
+ // Wraps the qrusty-client HTTP client with standard Node-RED patterns:
5
+ // status updates, async error handling, and config-vs-msg fallback.
6
+
7
+ const { QrustyClient } = require("qrusty-client");
8
+
9
+ /**
10
+ * Pick a value: prefer the node config, fall back to `msg.<name>`, then
11
+ * to `fallback`. Treats empty string / null / undefined as "not set".
12
+ *
13
+ * @param {*} configVal value from the Node-RED node config (may be "")
14
+ * @param {*} msgVal value from the incoming msg
15
+ * @param {*} [fallback] optional default when neither is set
16
+ * @returns {*}
17
+ */
18
+ function fromConfigOrMsg(configVal, msgVal, fallback) {
19
+ if (configVal !== undefined && configVal !== null && configVal !== "") {
20
+ return configVal;
21
+ }
22
+ if (msgVal !== undefined && msgVal !== null) {
23
+ return msgVal;
24
+ }
25
+ return fallback;
26
+ }
27
+
28
+ /**
29
+ * Coerce a value to a number if it looks numeric, else return undefined.
30
+ * Used for priority / maxRetries / timeoutSeconds config fields which are
31
+ * rendered as `<input type="number">` but arrive as strings.
32
+ */
33
+ function toNumberOrUndefined(value) {
34
+ if (value === undefined || value === null || value === "") return undefined;
35
+ const n = Number(value);
36
+ return Number.isNaN(n) ? undefined : n;
37
+ }
38
+
39
+ /**
40
+ * Register an async input handler on `node` that:
41
+ * 1. instantiates a QrustyClient from the server config's baseUrl,
42
+ * 2. runs the supplied `action(client, msg)` function,
43
+ * 3. stores the result in msg.payload and emits the msg,
44
+ * 4. updates node.status with blue → green (ok) / red (error),
45
+ * 5. forwards errors via `done(err)` for proper Node-RED catch semantics.
46
+ *
47
+ * If the server config is missing or invalid, the node enters a permanent
48
+ * "no server config" red-ring status and every subsequent input fails fast
49
+ * without making HTTP calls.
50
+ *
51
+ * @param {object} node the Node-RED node instance
52
+ * @param {object} serverConfig the resolved qrusty-server config node
53
+ * @param {Function} action async (client, msg) => any
54
+ */
55
+ function setupActionNode(node, serverConfig, action) {
56
+ if (!serverConfig || !serverConfig.baseUrl) {
57
+ node.status({ fill: "red", shape: "ring", text: "no server config" });
58
+ node.on("input", function (msg, send, done) {
59
+ const err = new Error(
60
+ "qrusty-server config is required but not configured",
61
+ );
62
+ if (done) {
63
+ done(err);
64
+ } else {
65
+ node.error(err, msg);
66
+ }
67
+ });
68
+ return;
69
+ }
70
+
71
+ node.on("input", async function (msg, send, done) {
72
+ node.status({ fill: "blue", shape: "dot", text: "requesting" });
73
+ try {
74
+ const client = new QrustyClient(serverConfig.baseUrl);
75
+ const result = await action(client, msg);
76
+ msg.payload = result;
77
+ node.status({ fill: "green", shape: "dot", text: "ok" });
78
+ send(msg);
79
+ if (done) done();
80
+ } catch (err) {
81
+ const statusText = err?.response?.status
82
+ ? `HTTP ${err.response.status}`
83
+ : err?.message || String(err);
84
+ node.status({ fill: "red", shape: "ring", text: statusText });
85
+ if (done) {
86
+ done(err);
87
+ } else {
88
+ node.error(err, msg);
89
+ }
90
+ }
91
+ });
92
+ }
93
+
94
+ module.exports = { setupActionNode, fromConfigOrMsg, toNumberOrUndefined };
package/package.json CHANGED
@@ -1,33 +1,63 @@
1
1
  {
2
2
  "name": "node-red-contrib-qrusty",
3
- "version": "0.19.19",
4
- "description": "Node-RED nodes for Qrusty priority queue server",
3
+ "version": "0.20.0",
4
+ "description": "Node-RED nodes for the Qrusty priority queue server",
5
5
  "author": "Gordon Greene <greeng3@obscure-reference.com>",
6
6
  "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/greeng3/qrusty.git",
10
+ "directory": "integrations/node-red"
11
+ },
7
12
  "keywords": [
8
13
  "node-red",
9
14
  "qrusty",
10
15
  "queue",
11
- "priority"
16
+ "priority-queue",
17
+ "message-queue"
18
+ ],
19
+ "engines": {
20
+ "node": ">=18"
21
+ },
22
+ "dependencies": {
23
+ "qrusty-client": "^0.20.0"
24
+ },
25
+ "devDependencies": {
26
+ "mocha": "^11.0.0",
27
+ "nock": "^14.0.0",
28
+ "node-red": "^4.0.0",
29
+ "node-red-node-test-helper": "^0.3.4"
30
+ },
31
+ "scripts": {
32
+ "test": "mocha \"test/**/*_spec.js\" --timeout 10000"
33
+ },
34
+ "files": [
35
+ "lib/",
36
+ "qrusty-*.js",
37
+ "qrusty-*.html",
38
+ "README.md",
39
+ "LICENSE"
12
40
  ],
13
41
  "node-red": {
42
+ "version": ">=3.0.0",
14
43
  "nodes": {
44
+ "qrusty-server": "qrusty-server.js",
15
45
  "qrusty-publish": "qrusty-publish.js",
16
46
  "qrusty-consume": "qrusty-consume.js",
17
47
  "qrusty-ack": "qrusty-ack.js",
18
48
  "qrusty-nack": "qrusty-nack.js",
49
+ "qrusty-ack-batch": "qrusty-ack-batch.js",
50
+ "qrusty-nack-batch": "qrusty-nack-batch.js",
19
51
  "qrusty-create-queue": "qrusty-create-queue.js",
20
52
  "qrusty-update-queue": "qrusty-update-queue.js",
21
53
  "qrusty-delete-queue": "qrusty-delete-queue.js",
22
54
  "qrusty-purge-queue": "qrusty-purge-queue.js",
55
+ "qrusty-purge-all": "qrusty-purge-all.js",
56
+ "qrusty-delete-all": "qrusty-delete-all.js",
23
57
  "qrusty-stats": "qrusty-stats.js",
24
58
  "qrusty-queue-stats": "qrusty-queue-stats.js",
25
59
  "qrusty-queue-metrics": "qrusty-queue-metrics.js",
26
60
  "qrusty-list-queues": "qrusty-list-queues.js",
27
- "qrusty-purge-all": "qrusty-purge-all.js",
28
- "qrusty-delete-all": "qrusty-delete-all.js",
29
- "qrusty-ack-batch": "qrusty-ack-batch.js",
30
- "qrusty-nack-batch": "qrusty-nack-batch.js",
31
61
  "qrusty-health": "qrusty-health.js"
32
62
  }
33
63
  }
@@ -0,0 +1,68 @@
1
+ <script type="text/javascript">
2
+ RED.nodes.registerType("qrusty-ack-batch", {
3
+ category: "qrusty",
4
+ color: "#d78a4e",
5
+ defaults: {
6
+ name: { value: "" },
7
+ server: { value: "", type: "qrusty-server", required: true },
8
+ queue: { value: "" },
9
+ consumerId: { value: "" },
10
+ },
11
+ inputs: 1,
12
+ outputs: 1,
13
+ icon: "font-awesome/fa-check-square",
14
+ label: function () {
15
+ return this.name || "qrusty ack batch";
16
+ },
17
+ paletteLabel: "ack batch",
18
+ });
19
+ </script>
20
+
21
+ <script type="text/html" data-template-name="qrusty-ack-batch">
22
+ <div class="form-row">
23
+ <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
24
+ <input type="text" id="node-input-name" placeholder="optional" />
25
+ </div>
26
+ <div class="form-row">
27
+ <label for="node-input-server"><i class="fa fa-server"></i> Server</label>
28
+ <input type="text" id="node-input-server" />
29
+ </div>
30
+ <div class="form-row">
31
+ <label for="node-input-queue"><i class="fa fa-list"></i> Queue</label>
32
+ <input
33
+ type="text"
34
+ id="node-input-queue"
35
+ placeholder="leave blank to use msg.queue"
36
+ />
37
+ </div>
38
+ <div class="form-row">
39
+ <label for="node-input-consumerId"
40
+ ><i class="fa fa-user"></i> Consumer ID</label
41
+ >
42
+ <input
43
+ type="text"
44
+ id="node-input-consumerId"
45
+ placeholder="default node-red-consumer"
46
+ />
47
+ </div>
48
+ </script>
49
+
50
+ <script type="text/html" data-help-name="qrusty-ack-batch">
51
+ <p>Acknowledges multiple messages at once.</p>
52
+ <h3>Inputs</h3>
53
+ <dl class="message-properties">
54
+ <dt>messageIds <span class="property-type">string[]</span></dt>
55
+ <dd>
56
+ The ids to ack. Supplied via <code>msg.messageIds</code>,
57
+ <code>msg.message_ids</code>, or <code>msg.payload</code> (if it
58
+ is itself an array).
59
+ </dd>
60
+ <dt class="optional">queue <span class="property-type">string</span></dt>
61
+ <dd>Queue holding the messages.</dd>
62
+ </dl>
63
+ <h3>Outputs</h3>
64
+ <dl class="message-properties">
65
+ <dt>payload <span class="property-type">object</span></dt>
66
+ <dd>Server response with counts of acked / not-found ids.</dd>
67
+ </dl>
68
+ </script>
@@ -1,10 +1,38 @@
1
- // Function node for batch-acknowledging messages in qrusty
2
- msg.url =
3
- "http://queue-server:6784/ack-batch/" + (msg.queue || "default_queue");
4
- msg.method = "POST";
5
- msg.payload = {
6
- consumer_id: msg.consumer_id || "node-red-consumer",
7
- message_ids: msg.messageIds || [],
1
+ // qrusty-ack-batch.js
2
+ //
3
+ // Batch-acknowledges multiple messages in one HTTP round trip.
4
+
5
+ const { setupActionNode, fromConfigOrMsg } = require("./lib/common");
6
+
7
+ module.exports = function (RED) {
8
+ function QrustyAckBatchNode(n) {
9
+ RED.nodes.createNode(this, n);
10
+ const node = this;
11
+ const server = RED.nodes.getNode(n.server);
12
+
13
+ setupActionNode(node, server, async (client, msg) => {
14
+ const queue = fromConfigOrMsg(n.queue, msg.queue);
15
+ if (!queue) throw new Error("queue is required");
16
+
17
+ const ids = Array.isArray(msg.messageIds)
18
+ ? msg.messageIds
19
+ : Array.isArray(msg.message_ids)
20
+ ? msg.message_ids
21
+ : Array.isArray(msg.payload)
22
+ ? msg.payload
23
+ : null;
24
+ if (!ids || ids.length === 0) {
25
+ throw new Error(
26
+ "messageIds array is required (set msg.messageIds, msg.message_ids, or msg.payload)",
27
+ );
28
+ }
29
+
30
+ const consumerId =
31
+ fromConfigOrMsg(n.consumerId, msg.consumer_id) || "node-red-consumer";
32
+
33
+ return await client.ackBatch(queue, consumerId, ids);
34
+ });
35
+ }
36
+
37
+ RED.nodes.registerType("qrusty-ack-batch", QrustyAckBatchNode);
8
38
  };
9
- msg.headers = { "Content-Type": "application/json" };
10
- return msg;
@@ -0,0 +1,66 @@
1
+ <script type="text/javascript">
2
+ RED.nodes.registerType("qrusty-ack", {
3
+ category: "qrusty",
4
+ color: "#d78a4e",
5
+ defaults: {
6
+ name: { value: "" },
7
+ server: { value: "", type: "qrusty-server", required: true },
8
+ queue: { value: "" },
9
+ consumerId: { value: "" },
10
+ },
11
+ inputs: 1,
12
+ outputs: 1,
13
+ icon: "font-awesome/fa-check",
14
+ label: function () {
15
+ return this.name || "qrusty ack";
16
+ },
17
+ paletteLabel: "ack",
18
+ });
19
+ </script>
20
+
21
+ <script type="text/html" data-template-name="qrusty-ack">
22
+ <div class="form-row">
23
+ <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
24
+ <input type="text" id="node-input-name" placeholder="optional" />
25
+ </div>
26
+ <div class="form-row">
27
+ <label for="node-input-server"><i class="fa fa-server"></i> Server</label>
28
+ <input type="text" id="node-input-server" />
29
+ </div>
30
+ <div class="form-row">
31
+ <label for="node-input-queue"><i class="fa fa-list"></i> Queue</label>
32
+ <input
33
+ type="text"
34
+ id="node-input-queue"
35
+ placeholder="leave blank to use msg.queue"
36
+ />
37
+ </div>
38
+ <div class="form-row">
39
+ <label for="node-input-consumerId"
40
+ ><i class="fa fa-user"></i> Consumer ID</label
41
+ >
42
+ <input
43
+ type="text"
44
+ id="node-input-consumerId"
45
+ placeholder="default node-red-consumer"
46
+ />
47
+ </div>
48
+ </script>
49
+
50
+ <script type="text/html" data-help-name="qrusty-ack">
51
+ <p>Acknowledges a Qrusty message.</p>
52
+ <h3>Inputs</h3>
53
+ <dl class="message-properties">
54
+ <dt>messageId / id <span class="property-type">string</span></dt>
55
+ <dd>The id of the message to ack (either <code>msg.messageId</code> or <code>msg.id</code>).</dd>
56
+ <dt class="optional">queue <span class="property-type">string</span></dt>
57
+ <dd>Queue holding the message (if not set on the node).</dd>
58
+ <dt class="optional">consumer_id <span class="property-type">string</span></dt>
59
+ <dd>Consumer identity that originally locked the message.</dd>
60
+ </dl>
61
+ <h3>Outputs</h3>
62
+ <dl class="message-properties">
63
+ <dt>payload <span class="property-type">boolean</span></dt>
64
+ <dd><code>true</code> on success, <code>false</code> if the server returned 404.</dd>
65
+ </dl>
66
+ </script>
package/qrusty-ack.js CHANGED
@@ -1,12 +1,33 @@
1
- // Function node for acknowledging a message in qrusty
2
- msg.url =
3
- "http://queue-server:6784/ack/" +
4
- (msg.queue || "default_queue") +
5
- "/" +
6
- msg.messageId;
7
- msg.method = "POST";
8
- msg.payload = {
9
- consumer_id: msg.consumer_id || "node-red-consumer",
1
+ // qrusty-ack.js
2
+ //
3
+ // Acknowledges a previously-consumed message. msg.payload becomes
4
+ // `true` on success or `false` if the server returned 404 (message
5
+ // already acked, lock expired, or id unknown).
6
+
7
+ const { setupActionNode, fromConfigOrMsg } = require("./lib/common");
8
+
9
+ module.exports = function (RED) {
10
+ function QrustyAckNode(n) {
11
+ RED.nodes.createNode(this, n);
12
+ const node = this;
13
+ const server = RED.nodes.getNode(n.server);
14
+
15
+ setupActionNode(node, server, async (client, msg) => {
16
+ const queue = fromConfigOrMsg(n.queue, msg.queue);
17
+ if (!queue) throw new Error("queue is required");
18
+ const messageId = fromConfigOrMsg(
19
+ undefined,
20
+ msg.messageId ?? msg.id ?? msg.message_id,
21
+ );
22
+ if (!messageId) {
23
+ throw new Error("messageId is required (set msg.messageId or msg.id)");
24
+ }
25
+ const consumerId =
26
+ fromConfigOrMsg(n.consumerId, msg.consumer_id) || "node-red-consumer";
27
+
28
+ return await client.ack(queue, messageId, consumerId);
29
+ });
30
+ }
31
+
32
+ RED.nodes.registerType("qrusty-ack", QrustyAckNode);
10
33
  };
11
- msg.headers = { "Content-Type": "application/json" };
12
- return msg;
@@ -0,0 +1,76 @@
1
+ <script type="text/javascript">
2
+ RED.nodes.registerType("qrusty-consume", {
3
+ category: "qrusty",
4
+ color: "#d78a4e",
5
+ defaults: {
6
+ name: { value: "" },
7
+ server: { value: "", type: "qrusty-server", required: true },
8
+ queue: { value: "" },
9
+ consumerId: { value: "" },
10
+ timeoutSeconds: { value: "" },
11
+ },
12
+ inputs: 1,
13
+ outputs: 1,
14
+ icon: "font-awesome/fa-inbox",
15
+ label: function () {
16
+ return this.name || "qrusty consume";
17
+ },
18
+ paletteLabel: "consume",
19
+ });
20
+ </script>
21
+
22
+ <script type="text/html" data-template-name="qrusty-consume">
23
+ <div class="form-row">
24
+ <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
25
+ <input type="text" id="node-input-name" placeholder="optional" />
26
+ </div>
27
+ <div class="form-row">
28
+ <label for="node-input-server"><i class="fa fa-server"></i> Server</label>
29
+ <input type="text" id="node-input-server" />
30
+ </div>
31
+ <div class="form-row">
32
+ <label for="node-input-queue"><i class="fa fa-list"></i> Queue</label>
33
+ <input
34
+ type="text"
35
+ id="node-input-queue"
36
+ placeholder="leave blank to use msg.queue"
37
+ />
38
+ </div>
39
+ <div class="form-row">
40
+ <label for="node-input-consumerId"
41
+ ><i class="fa fa-user"></i> Consumer ID</label
42
+ >
43
+ <input
44
+ type="text"
45
+ id="node-input-consumerId"
46
+ placeholder="default node-red-consumer"
47
+ />
48
+ </div>
49
+ <div class="form-row">
50
+ <label for="node-input-timeoutSeconds"
51
+ ><i class="fa fa-clock-o"></i> Lock timeout (s)</label
52
+ >
53
+ <input type="number" id="node-input-timeoutSeconds" placeholder="30" />
54
+ </div>
55
+ </script>
56
+
57
+ <script type="text/html" data-help-name="qrusty-consume">
58
+ <p>Pops one message from a Qrusty queue.</p>
59
+ <h3>Inputs</h3>
60
+ <dl class="message-properties">
61
+ <dt class="optional">queue <span class="property-type">string</span></dt>
62
+ <dd>Queue to read from (if not set on the node).</dd>
63
+ <dt class="optional">consumer_id <span class="property-type">string</span></dt>
64
+ <dd>Consumer identity used by the lock ownership check.</dd>
65
+ <dt class="optional">timeout_seconds <span class="property-type">number</span></dt>
66
+ <dd>How long the server locks the popped message before auto-unlock.</dd>
67
+ </dl>
68
+ <h3>Outputs</h3>
69
+ <dl class="message-properties">
70
+ <dt>payload <span class="property-type">object | null</span></dt>
71
+ <dd>
72
+ The popped message (<code>{ id, payload, retry_count }</code>) or
73
+ <code>null</code> when the queue is empty.
74
+ </dd>
75
+ </dl>
76
+ </script>