@halsystems/red-bacnet 2.2.1 → 2.2.2-alpha.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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.2.2-alpha.0]
|
|
4
|
+
### Added
|
|
5
|
+
- `CoalescedJobQueue` added `onStart` and `onStop` hooks
|
|
6
|
+
- auto sync to `red-bacnet-public` repo
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
- `discover device` fixed `#IAmHandler` memory leak issue
|
|
10
|
+
- `CICD` Fixed broken pipeline due to package registry caching / propagation issue
|
|
11
|
+
|
|
3
12
|
## [2.2.1]
|
|
4
13
|
### Fixed
|
|
5
14
|
- Fixed unhandled promise rejections in BACnet `jobs` that could hang the job queue or crash Node-RED; errors are now reported instead.
|
package/common/core/constant.js
CHANGED
|
@@ -31,7 +31,5 @@ module.exports = {
|
|
|
31
31
|
|
|
32
32
|
// job error
|
|
33
33
|
ERR_CONSTRUCT_ABSTRACT_JOB: 'Cannot construct abstract Job class',
|
|
34
|
-
ERR_ONSTART_NOT_IMPLEMENTED: 'OnStart method is not implemented.',
|
|
35
|
-
ERR_ONSTOP_NOT_IMPLEMENTED: 'OnStop method is not implemented.',
|
|
36
34
|
ERR_EXECUTE_NOT_IMPLEMENTED: 'Execute method is not implemented.',
|
|
37
35
|
}
|
package/common/job/core.js
CHANGED
|
@@ -3,8 +3,7 @@ require('./_alias.js');
|
|
|
3
3
|
|
|
4
4
|
const { print } = require('@root/common/core/util.js');
|
|
5
5
|
const {
|
|
6
|
-
ERR_CONSTRUCT_ABSTRACT_JOB,
|
|
7
|
-
ERR_ONSTOP_NOT_IMPLEMENTED, ERR_EXECUTE_NOT_IMPLEMENTED
|
|
6
|
+
ERR_CONSTRUCT_ABSTRACT_JOB, ERR_EXECUTE_NOT_IMPLEMENTED
|
|
8
7
|
} = require('@root/common/core/constant.js')
|
|
9
8
|
|
|
10
9
|
/**
|
|
@@ -51,10 +50,8 @@ class BaseJob {
|
|
|
51
50
|
*
|
|
52
51
|
* @async
|
|
53
52
|
* @returns {Promise<void>}
|
|
54
|
-
* @throws {Error} If not implemented by subclass.
|
|
55
53
|
*/
|
|
56
54
|
async onStart() {
|
|
57
|
-
throw new Error(ERR_ONSTART_NOT_IMPLEMENTED);
|
|
58
55
|
}
|
|
59
56
|
|
|
60
57
|
/**
|
|
@@ -79,10 +76,8 @@ class BaseJob {
|
|
|
79
76
|
*
|
|
80
77
|
* @async
|
|
81
78
|
* @returns {Promise<void>}
|
|
82
|
-
* @throws {Error} If not implemented by subclass.
|
|
83
79
|
*/
|
|
84
80
|
async onStop() {
|
|
85
|
-
throw new Error(ERR_ONSTOP_NOT_IMPLEMENTED);
|
|
86
81
|
}
|
|
87
82
|
}
|
|
88
83
|
|
|
@@ -160,9 +155,12 @@ class CoalescedJobQueue {
|
|
|
160
155
|
|
|
161
156
|
const job = this.queue.splice(jobIndex, 1)[0];
|
|
162
157
|
try {
|
|
158
|
+
await job.task.onStart();
|
|
163
159
|
await job.task.execute();
|
|
164
160
|
} catch (error) {
|
|
165
161
|
console.error(`Error executing job ${job.id}:`, error);
|
|
162
|
+
} finally {
|
|
163
|
+
await job.task.onStop();
|
|
166
164
|
}
|
|
167
165
|
}
|
|
168
166
|
await new Promise(resolve => setTimeout(resolve, this.delay));
|
|
@@ -22,6 +22,7 @@ module.exports = {
|
|
|
22
22
|
knownDevices = new Set();
|
|
23
23
|
discoverList = [];
|
|
24
24
|
discoveredDevices = [];
|
|
25
|
+
#boundIAmHandler;
|
|
25
26
|
|
|
26
27
|
/**
|
|
27
28
|
* Construct a DiscoverDeviceJob.
|
|
@@ -46,17 +47,17 @@ module.exports = {
|
|
|
46
47
|
this.highLimit = highLimit
|
|
47
48
|
this.whoIsTimeout = whoIsTimeout
|
|
48
49
|
this.name = name
|
|
50
|
+
this.#boundIAmHandler = this.#iAmHandler.bind(this)
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
async onStart() {
|
|
52
|
-
this.client.on(EVENT_I_AM, this.#
|
|
54
|
+
this.client.on(EVENT_I_AM, this.#boundIAmHandler)
|
|
53
55
|
}
|
|
54
56
|
async onStop() {
|
|
55
|
-
this.client.removeListener(EVENT_I_AM, this.#
|
|
57
|
+
this.client.removeListener(EVENT_I_AM, this.#boundIAmHandler)
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
async execute() {
|
|
59
|
-
// discover device job will be reused
|
|
60
61
|
this.knownDevices.clear();
|
|
61
62
|
this.discoverList = [];
|
|
62
63
|
this.discoveredDevices = [];
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@ const { DiscoverDeviceJob } = require('@root/common/job/discover_device.js')
|
|
|
9
9
|
const { getQueue } = require('@root/common/job/global_queue_manager.js')
|
|
10
10
|
const { generateUniqueJobId } = require('@root/common/func.js')
|
|
11
11
|
const {
|
|
12
|
-
EVENT_UPDATE_STATUS, EVENT_ERROR, EVENT_INPUT, EVENT_OUTPUT
|
|
12
|
+
EVENT_UPDATE_STATUS, EVENT_ERROR, EVENT_INPUT, EVENT_OUTPUT
|
|
13
13
|
} = require('@root/common/core/constant.js')
|
|
14
14
|
|
|
15
15
|
|
|
@@ -37,18 +37,6 @@ module.exports = function (RED) {
|
|
|
37
37
|
|
|
38
38
|
// configure job queue - use global queue
|
|
39
39
|
this.job = getQueue();
|
|
40
|
-
|
|
41
|
-
// init task
|
|
42
|
-
this.task = new DiscoverDeviceJob(
|
|
43
|
-
this.client,
|
|
44
|
-
this.#eventEmitter,
|
|
45
|
-
null,
|
|
46
|
-
this.network,
|
|
47
|
-
this.lowLimit,
|
|
48
|
-
this.highLimit,
|
|
49
|
-
this.whoIsTimeout,
|
|
50
|
-
);
|
|
51
|
-
this.task.onStart();
|
|
52
40
|
}
|
|
53
41
|
|
|
54
42
|
#subscribeListeners() {
|
|
@@ -57,11 +45,6 @@ module.exports = function (RED) {
|
|
|
57
45
|
*/
|
|
58
46
|
// @ts-ignore
|
|
59
47
|
this.on(EVENT_INPUT, async function (msg) {
|
|
60
|
-
/*
|
|
61
|
-
BACnet iAm handler is causing memory leak due to unable to detach after use
|
|
62
|
-
as a result, workaround is introduce before strategy to reuse discoverDeviceJob instead
|
|
63
|
-
of creating new one every time onInput is triggered
|
|
64
|
-
*/
|
|
65
48
|
const jobId = (typeof msg.id === 'string' || typeof msg.id === 'number') ? msg.id : this.jobId;
|
|
66
49
|
|
|
67
50
|
if (this.job.queue.map(item => item.id).includes(jobId)) {
|
|
@@ -70,14 +53,19 @@ module.exports = function (RED) {
|
|
|
70
53
|
return;
|
|
71
54
|
}
|
|
72
55
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
56
|
+
const task = new DiscoverDeviceJob(
|
|
57
|
+
this.client,
|
|
58
|
+
this.#eventEmitter,
|
|
59
|
+
msg,
|
|
60
|
+
this.network,
|
|
61
|
+
this.lowLimit,
|
|
62
|
+
this.highLimit,
|
|
63
|
+
this.whoIsTimeout,
|
|
64
|
+
);
|
|
77
65
|
|
|
78
66
|
this.job.addJob({
|
|
79
67
|
id: jobId,
|
|
80
|
-
task:
|
|
68
|
+
task: task,
|
|
81
69
|
priority: Number.isFinite(msg.priority) ? msg.priority : 5,
|
|
82
70
|
});
|
|
83
71
|
|
|
@@ -85,11 +73,6 @@ module.exports = function (RED) {
|
|
|
85
73
|
this.status({ fill: 'yellow', shape: 'dot', text: `in queue` });
|
|
86
74
|
});
|
|
87
75
|
|
|
88
|
-
// @ts-ignore
|
|
89
|
-
this.on(EVENT_CLOSE, () => {
|
|
90
|
-
this.task.onStop();
|
|
91
|
-
})
|
|
92
|
-
|
|
93
76
|
this.#eventEmitter.on(EVENT_OUTPUT, (msg) => {
|
|
94
77
|
// @ts-ignore
|
|
95
78
|
this.send(msg);
|