@zintrust/queue-monitor 0.4.75 → 0.4.86

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.
@@ -1,8 +1,36 @@
1
1
  import { Logger } from '@zintrust/core';
2
2
  export const ALL_QUEUES = '__all__';
3
3
  const subscriptions = new Map();
4
+ const channels = new Map();
5
+ const objectIds = new WeakMap();
6
+ let nextObjectId = 0;
4
7
  const isAllQueuesSelection = (queue) => queue === ALL_QUEUES;
5
8
  const sortJobsByTimestamp = (jobs) => jobs.toSorted((left, right) => right.timestamp - left.timestamp);
9
+ const getObjectId = (value) => {
10
+ const existing = objectIds.get(value);
11
+ if (existing !== undefined)
12
+ return existing;
13
+ nextObjectId += 1;
14
+ objectIds.set(value, nextObjectId);
15
+ return nextObjectId;
16
+ };
17
+ const buildChannelKey = (config) => {
18
+ const snapshotId = getObjectId(config.getSnapshot);
19
+ const locksId = getObjectId(config.getLocks);
20
+ const jobsId = getObjectId(config.getRecentJobsForQueue);
21
+ const metricsId = getObjectId(config.metrics);
22
+ const driverId = getObjectId(config.driver);
23
+ return [
24
+ config.queue,
25
+ config.pattern,
26
+ String(config.intervalMs),
27
+ String(snapshotId),
28
+ String(locksId),
29
+ String(jobsId),
30
+ String(metricsId),
31
+ String(driverId),
32
+ ].join('::');
33
+ };
6
34
  export async function getRecentJobsForSelection(queueName, metrics, driver, queueNames) {
7
35
  if (!isAllQueuesSelection(queueName)) {
8
36
  return getRecentJobsForQueue(queueName, metrics, driver);
@@ -36,48 +64,92 @@ const buildSnapshotPayload = async (config) => {
36
64
  locks: await getLocks(pattern),
37
65
  };
38
66
  };
39
- const pushSnapshot = async (subscription) => {
67
+ const pushSnapshot = async (channel) => {
40
68
  try {
41
- subscription.callback(await buildSnapshotPayload(subscription.config));
69
+ channel.pending ??= buildSnapshotPayload(channel.config);
70
+ const payload = await channel.pending;
71
+ channel.lastPayload = payload;
72
+ channel.callbacks.forEach((callback) => {
73
+ try {
74
+ callback(payload);
75
+ }
76
+ catch (err) {
77
+ Logger.error('QueueMonitoringService.pushSnapshot callback failed', err);
78
+ }
79
+ });
42
80
  }
43
81
  catch (err) {
44
82
  Logger.error('QueueMonitoringService.pushSnapshot failed', err);
45
83
  }
84
+ finally {
85
+ channel.pending = null;
86
+ }
46
87
  };
47
- const startPolling = (subscription) => {
48
- if (subscription.interval)
88
+ const startPolling = (channel) => {
89
+ if (channel.interval)
49
90
  return;
50
- void pushSnapshot(subscription);
51
- subscription.interval = setInterval(() => {
52
- void pushSnapshot(subscription);
53
- }, subscription.config.intervalMs);
91
+ void pushSnapshot(channel);
92
+ channel.interval = setInterval(() => {
93
+ void pushSnapshot(channel);
94
+ }, channel.config.intervalMs);
54
95
  };
55
- const stopPolling = (subscription) => {
56
- if (!subscription.interval)
96
+ const stopPolling = (channel) => {
97
+ if (!channel.interval)
57
98
  return;
58
- clearInterval(subscription.interval);
59
- subscription.interval = null;
99
+ clearInterval(channel.interval);
100
+ channel.interval = null;
101
+ };
102
+ const getOrCreateChannel = (config) => {
103
+ const key = buildChannelKey(config);
104
+ const existing = channels.get(key);
105
+ if (existing)
106
+ return existing;
107
+ const channel = {
108
+ key,
109
+ config,
110
+ callbacks: new Set(),
111
+ interval: null,
112
+ lastPayload: null,
113
+ pending: null,
114
+ };
115
+ channels.set(key, channel);
116
+ return channel;
60
117
  };
61
118
  export const QueueMonitoringService = Object.freeze({
62
119
  subscribe(callback, config) {
63
120
  const existing = subscriptions.get(callback);
64
121
  if (existing) {
65
- stopPolling(existing);
122
+ const existingChannel = channels.get(existing.channelKey);
123
+ existingChannel?.callbacks.delete(callback);
124
+ if (existingChannel?.callbacks.size === 0) {
125
+ stopPolling(existingChannel);
126
+ channels.delete(existingChannel.key);
127
+ }
66
128
  subscriptions.delete(callback);
67
129
  }
130
+ const channel = getOrCreateChannel(config);
131
+ channel.callbacks.add(callback);
68
132
  const subscription = {
69
133
  callback,
70
134
  config,
71
- interval: null,
135
+ channelKey: channel.key,
72
136
  };
73
137
  subscriptions.set(callback, subscription);
74
- startPolling(subscription);
138
+ if (channel.lastPayload) {
139
+ callback(channel.lastPayload);
140
+ }
141
+ startPolling(channel);
75
142
  },
76
143
  unsubscribe(callback) {
77
144
  const subscription = subscriptions.get(callback);
78
145
  if (!subscription)
79
146
  return;
80
- stopPolling(subscription);
147
+ const channel = channels.get(subscription.channelKey);
148
+ channel?.callbacks.delete(callback);
149
+ if (channel?.callbacks.size === 0) {
150
+ stopPolling(channel);
151
+ channels.delete(channel.key);
152
+ }
81
153
  subscriptions.delete(callback);
82
154
  },
83
155
  });
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@zintrust/queue-monitor",
3
- "version": "0.4.75",
4
- "buildDate": "2026-04-07T17:13:57.726Z",
3
+ "version": "0.4.86",
4
+ "buildDate": "2026-04-09T08:06:22.134Z",
5
5
  "buildEnvironment": {
6
6
  "node": "v20.20.2",
7
7
  "platform": "linux",
8
8
  "arch": "x64"
9
9
  },
10
10
  "git": {
11
- "commit": "f910e7ec",
11
+ "commit": "a456e7ec",
12
12
  "branch": "master"
13
13
  },
14
14
  "package": {
@@ -29,8 +29,8 @@
29
29
  "sha256": "26a91f1b41d8a976a9e8fabaedc3fe6dc955c700499f0afc1a16fb91c9848665"
30
30
  },
31
31
  "QueueMonitoringService.js": {
32
- "size": 6679,
33
- "sha256": "edd069c1229071078223cd23cbb7bdae9cbb2431ae603ab35f0cfcb7cd1f6ffe"
32
+ "size": 8900,
33
+ "sha256": "0d00a27755a372ce77bb5921ce25fe024d3e57274cd48f963457f76bf5486e4b"
34
34
  },
35
35
  "connection.d.ts": {
36
36
  "size": 107,
@@ -62,7 +62,7 @@
62
62
  },
63
63
  "index.js": {
64
64
  "size": 12870,
65
- "sha256": "b4ece7788fcd3f7f329c324f5c4cc0e807619d482211cb5d7ceb21303477461c"
65
+ "sha256": "ff398e2a1d48d2ed2d469a84277d069a6e7b171f48679d2d1b6b6d39a8e53b67"
66
66
  },
67
67
  "metrics.d.ts": {
68
68
  "size": 868,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zintrust/queue-monitor",
3
- "version": "0.4.75",
3
+ "version": "0.4.86",
4
4
  "description": "Queue monitoring package for ZinTrust with BullMQ and Redis.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -20,7 +20,7 @@
20
20
  "node": ">=20.0.0"
21
21
  },
22
22
  "peerDependencies": {
23
- "@zintrust/core": "^0.4.74"
23
+ "@zintrust/core": "^0.4.84"
24
24
  },
25
25
  "publishConfig": {
26
26
  "access": "public"