@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.
@@ -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
  }
@@ -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, ERR_ONSTART_NOT_IMPLEMENTED,
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.#iAmHandler.bind(this))
54
+ this.client.on(EVENT_I_AM, this.#boundIAmHandler)
53
55
  }
54
56
  async onStop() {
55
- this.client.removeListener(EVENT_I_AM, this.#iAmHandler.bind(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 = [];
@@ -72,7 +72,7 @@ module.exports = {
72
72
  getQueue() {
73
73
  if (!globalQueue) {
74
74
  stopping = false;
75
- globalQueue = new CoalescedJobQueue(100, true, 5);
75
+ globalQueue = new CoalescedJobQueue(50, true, 5);
76
76
  }
77
77
 
78
78
  if (!globalQueue.isRunning && !stopping) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@halsystems/red-bacnet",
3
- "version": "2.2.1",
3
+ "version": "2.2.2-alpha.0",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org/",
6
6
  "access": "public"
@@ -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, EVENT_CLOSE
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
- this.task.network = (msg.network === undefined) ? this.network : msg.network;
74
- this.task.lowLimit = (msg.lowLimit === undefined) ? this.lowLimit : msg.lowLimit;
75
- this.task.highLimit = (msg.highLimit === undefined) ? this.highLimit : msg.highLimit;
76
- this.task.msg = msg;
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: this.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);