@yarkivaev/scada 2.4.5 → 2.4.7
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/package.json +1 -1
- package/src/infrastructure/ingest/pipelines/segmentPipeline.js +6 -3
- package/src/infrastructure/ingest/pipelines/stompOptions.js +1 -1
- package/src/infrastructure/ingest/telemetry/amqpMetricsIngest.js +4 -1
- package/src/infrastructure/streams/stompBody.js +2 -1
- package/src/infrastructure/streams/stompSource.js +3 -1
package/package.json
CHANGED
|
@@ -43,8 +43,8 @@ function segmentSinks(postgres, pool) {
|
|
|
43
43
|
/**
|
|
44
44
|
* Pipeline for streaming STOMP segment data to PostgreSQL segments table.
|
|
45
45
|
* Subscribes to the durable ingest queue so shovel traffic survives consumer gaps.
|
|
46
|
-
* Pending heartbeats are coalesced per machine.
|
|
47
|
-
*
|
|
46
|
+
* Pending heartbeats are coalesced per machine. Machine lanes run in parallel;
|
|
47
|
+
* only storage execution consumes its watchdog, not bounded lane queue wait.
|
|
48
48
|
*
|
|
49
49
|
* @param {string} stomp - STOMP broker URL
|
|
50
50
|
* @param {string} postgres - PostgreSQL connection URL
|
|
@@ -71,7 +71,10 @@ export default function segmentPipeline(stomp, postgres, pool, config) {
|
|
|
71
71
|
interval: config.interval
|
|
72
72
|
});
|
|
73
73
|
const destination = config.segmentsDestination || segmentsIngestDestination;
|
|
74
|
-
|
|
74
|
+
// Each admitted frame can flush one heartbeat and then persist itself; prefetch bounds queue depth.
|
|
75
|
+
const deliveryTimeoutMs = Math.min(2147483647, (config.acceptTimeoutMs ?? 10000) * (config.prefetch ?? 32) * 2);
|
|
76
|
+
source = stompSource(stomp, destination, coalesce,
|
|
77
|
+
stompOptions(config, { serial: false, manualAck: true, deliveryTimeoutMs }));
|
|
75
78
|
const silence = silentOpenWatch(closeSilentOpen(pool), budget, {
|
|
76
79
|
intervalMs: (config.poll || 5) * 1000
|
|
77
80
|
});
|
|
@@ -3,7 +3,7 @@ export default function stompOptions(config, overrides = {}) {
|
|
|
3
3
|
const options = { login: config.login, passcode: config.passcode, host: config.host,
|
|
4
4
|
prefetch: config.prefetch, maxMessageBytes: config.maxMessageBytes,
|
|
5
5
|
maxPendingBytes: config.maxPendingBytes, budget: config.budget,
|
|
6
|
-
acceptTimeoutMs: config.acceptTimeoutMs, stopTimeoutMs: config.stopTimeoutMs,
|
|
6
|
+
acceptTimeoutMs: config.acceptTimeoutMs, deliveryTimeoutMs: config.deliveryTimeoutMs, stopTimeoutMs: config.stopTimeoutMs,
|
|
7
7
|
onError: config.onError, onFatal: config.onFatal, onState: config.onState, ...overrides };
|
|
8
8
|
return Object.fromEntries(Object.entries(options).filter(([, value]) => { return value !== undefined; }));
|
|
9
9
|
}
|
|
@@ -56,7 +56,10 @@ export function telemetryConsumer(codec, channel, onSeen) {
|
|
|
56
56
|
*/
|
|
57
57
|
export default function amqpMetricsIngest(amqpUrl, queue, sink, options = {}) {
|
|
58
58
|
const prefetch = options.prefetch || 32;
|
|
59
|
-
|
|
59
|
+
// Unacknowledged deliveries occupy the broker window until the batch commits.
|
|
60
|
+
// A larger batch can never fill and would throttle ingestion to the flush timer.
|
|
61
|
+
const size = Math.min(options.size ?? 100, prefetch);
|
|
62
|
+
const collector = ingestBatch(sink, { ...options, size });
|
|
60
63
|
const codec = metricsCodec(collector);
|
|
61
64
|
const session = amqpSource(amqpUrl, queue, {
|
|
62
65
|
accept(delivery) {
|
|
@@ -3,8 +3,9 @@ import budgetAccept from './budgetAccept.js';
|
|
|
3
3
|
|
|
4
4
|
export function stompSettings(options, prefetch) {
|
|
5
5
|
const config = { acceptTimeoutMs: 10000, stopTimeoutMs: 5000, maxMessageBytes: 1048576, ...options };
|
|
6
|
+
config.deliveryTimeoutMs ??= config.acceptTimeoutMs;
|
|
6
7
|
config.maxPendingBytes ??= prefetch * config.maxMessageBytes;
|
|
7
|
-
['acceptTimeoutMs', 'stopTimeoutMs', 'maxMessageBytes', 'maxPendingBytes'].forEach((key) => { positive(config[key], key); });
|
|
8
|
+
['acceptTimeoutMs', 'deliveryTimeoutMs', 'stopTimeoutMs', 'maxMessageBytes', 'maxPendingBytes'].forEach((key) => { positive(config[key], key); });
|
|
8
9
|
if (!Number.isSafeInteger(config.maxMessageBytes) || !Number.isSafeInteger(config.maxPendingBytes)) {
|
|
9
10
|
throw new TypeError('STOMP byte capacities must be safe integers');
|
|
10
11
|
}
|
|
@@ -85,7 +85,7 @@ async function deliver(ctx, body) {
|
|
|
85
85
|
try {
|
|
86
86
|
await deadline(Promise.resolve().then(() => {
|
|
87
87
|
return acceptStomp(ctx, body, settle);
|
|
88
|
-
}), ctx.lifecycle.
|
|
88
|
+
}), ctx.lifecycle.deliveryTimeoutMs, 'STOMP acceptance', (error) => {
|
|
89
89
|
ctx.lifecycle.fail(error);
|
|
90
90
|
});
|
|
91
91
|
if (!ctx.manualAck) {
|
|
@@ -139,6 +139,8 @@ function bind(channel, destination, collector, delivery) {
|
|
|
139
139
|
* Messages are `{destination, payload, settle}`. Default ack-after-accept;
|
|
140
140
|
* with `manualAck` the collector owns settle. Arrivals enqueue in
|
|
141
141
|
* subscribe order. With `serial: false` persist may overlap after enqueue.
|
|
142
|
+
* deliveryTimeoutMs optionally includes bounded collector queue wait; body reads
|
|
143
|
+
* retain acceptTimeoutMs. Collectors owning an execution deadline can separate them.
|
|
142
144
|
* A finite prefetch (default 32) bounds unacknowledged broker deliveries.
|
|
143
145
|
*
|
|
144
146
|
* @param {string} url - STOMP broker URL
|