@cap-js-community/event-queue 1.9.2 → 1.9.4
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/config.js +25 -12
- package/src/initialize.js +1 -0
- package/src/runner/runner.js +4 -4
- package/src/shared/distributedLock.js +2 -3
- package/src/shared/openTelemetry.js +0 -6
- package/src/shared/redis.js +5 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cap-js-community/event-queue",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.4",
|
|
4
4
|
"description": "An event queue that enables secure transactional processing of asynchronous and periodic events, featuring instant event processing with Redis Pub/Sub and load distribution across all application instances.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"types": "src/index.d.ts",
|
package/src/config.js
CHANGED
|
@@ -10,9 +10,12 @@ const { Priorities } = require("./constants");
|
|
|
10
10
|
|
|
11
11
|
const FOR_UPDATE_TIMEOUT = 10;
|
|
12
12
|
const GLOBAL_TX_TIMEOUT = 30 * 60 * 1000;
|
|
13
|
-
const
|
|
13
|
+
const REDIS_PREFIX = "EVENT_QUEUE";
|
|
14
|
+
const REDIS_CONFIG_CHANNEL = "CONFIG_CHANNEL";
|
|
14
15
|
const REDIS_OFFBOARD_TENANT_CHANNEL = "REDIS_OFFBOARD_TENANT_CHANNEL";
|
|
15
|
-
const REDIS_CONFIG_BLOCKLIST_CHANNEL = "
|
|
16
|
+
const REDIS_CONFIG_BLOCKLIST_CHANNEL = "REDIS_CONFIG_BLOCKLIST_CHANNEL";
|
|
17
|
+
const COMMAND_BLOCK = "EVENT_BLOCK";
|
|
18
|
+
const COMMAND_UNBLOCK = "EVENT_UNBLOCK";
|
|
16
19
|
const COMPONENT_NAME = "/eventQueue/config";
|
|
17
20
|
const MIN_INTERVAL_SEC = 10;
|
|
18
21
|
const DEFAULT_LOAD = 1;
|
|
@@ -22,8 +25,6 @@ const DEFAULT_KEEP_ALIVE_INTERVAL = 60;
|
|
|
22
25
|
const DEFAULT_MAX_FACTOR_STUCK_2_KEEP_ALIVE_INTERVAL = 3.5;
|
|
23
26
|
const DEFAULT_INHERIT_TRACE_CONTEXT = true;
|
|
24
27
|
const SUFFIX_PERIODIC = "_PERIODIC";
|
|
25
|
-
const COMMAND_BLOCK = "EVENT_QUEUE_EVENT_BLOCK";
|
|
26
|
-
const COMMAND_UNBLOCK = "EVENT_QUEUE_EVENT_UNBLOCK";
|
|
27
28
|
const CAP_EVENT_TYPE = "CAP_OUTBOX";
|
|
28
29
|
const CAP_PARALLEL_DEFAULT = 5;
|
|
29
30
|
const DELETE_TENANT_BLOCK_AFTER_MS = 5 * 60 * 1000;
|
|
@@ -67,6 +68,7 @@ class Config {
|
|
|
67
68
|
#unsubscribeHandlers = [];
|
|
68
69
|
#unsubscribedTenants = {};
|
|
69
70
|
#cronTimezone;
|
|
71
|
+
#redisNamespace;
|
|
70
72
|
#publishEventBlockList;
|
|
71
73
|
#crashOnRedisUnavailable;
|
|
72
74
|
#tenantIdFilterTokenInfoCb;
|
|
@@ -143,7 +145,7 @@ class Config {
|
|
|
143
145
|
|
|
144
146
|
attachConfigChangeHandler() {
|
|
145
147
|
this.#attachBlockListChangeHandler();
|
|
146
|
-
redis.subscribeRedisChannel(this
|
|
148
|
+
redis.subscribeRedisChannel(this.redisOptions, REDIS_CONFIG_CHANNEL, (messageData) => {
|
|
147
149
|
try {
|
|
148
150
|
const { key, value } = JSON.parse(messageData);
|
|
149
151
|
if (this[key] !== value) {
|
|
@@ -160,7 +162,7 @@ class Config {
|
|
|
160
162
|
|
|
161
163
|
attachRedisUnsubscribeHandler() {
|
|
162
164
|
this.#logger.info("attached redis handle for unsubscribe events");
|
|
163
|
-
redis.subscribeRedisChannel(this
|
|
165
|
+
redis.subscribeRedisChannel(this.redisOptions, REDIS_OFFBOARD_TENANT_CHANNEL, (messageData) => {
|
|
164
166
|
try {
|
|
165
167
|
const { tenantId } = JSON.parse(messageData);
|
|
166
168
|
this.#logger.info("received unsubscribe broadcast event", { tenantId });
|
|
@@ -190,7 +192,7 @@ class Config {
|
|
|
190
192
|
handleUnsubscribe(tenantId) {
|
|
191
193
|
if (this.redisEnabled) {
|
|
192
194
|
redis
|
|
193
|
-
.publishMessage(this
|
|
195
|
+
.publishMessage(this.redisOptions, REDIS_OFFBOARD_TENANT_CHANNEL, JSON.stringify({ tenantId }))
|
|
194
196
|
.catch((error) => {
|
|
195
197
|
this.#logger.error(`publishing tenant unsubscribe failed. tenantId: ${tenantId}`, error);
|
|
196
198
|
});
|
|
@@ -208,13 +210,13 @@ class Config {
|
|
|
208
210
|
this.#logger.info("redis not connected, config change won't be published", { key, value });
|
|
209
211
|
return;
|
|
210
212
|
}
|
|
211
|
-
redis.publishMessage(this
|
|
213
|
+
redis.publishMessage(this.redisOptions, REDIS_CONFIG_CHANNEL, JSON.stringify({ key, value })).catch((error) => {
|
|
212
214
|
this.#logger.error(`publishing config change failed key: ${key}, value: ${value}`, error);
|
|
213
215
|
});
|
|
214
216
|
}
|
|
215
217
|
|
|
216
218
|
#attachBlockListChangeHandler() {
|
|
217
|
-
redis.subscribeRedisChannel(this
|
|
219
|
+
redis.subscribeRedisChannel(this.redisOptions, REDIS_CONFIG_BLOCKLIST_CHANNEL, (messageData) => {
|
|
218
220
|
try {
|
|
219
221
|
const { command, key, tenant } = JSON.parse(messageData);
|
|
220
222
|
if (command === COMMAND_BLOCK) {
|
|
@@ -244,7 +246,7 @@ class Config {
|
|
|
244
246
|
|
|
245
247
|
redis
|
|
246
248
|
.publishMessage(
|
|
247
|
-
this
|
|
249
|
+
this.redisOptions,
|
|
248
250
|
REDIS_CONFIG_BLOCKLIST_CHANNEL,
|
|
249
251
|
JSON.stringify({ command: COMMAND_BLOCK, key, tenant })
|
|
250
252
|
)
|
|
@@ -277,7 +279,7 @@ class Config {
|
|
|
277
279
|
|
|
278
280
|
redis
|
|
279
281
|
.publishMessage(
|
|
280
|
-
this
|
|
282
|
+
this.redisOptions,
|
|
281
283
|
REDIS_CONFIG_BLOCKLIST_CHANNEL,
|
|
282
284
|
JSON.stringify({ command: COMMAND_UNBLOCK, key, tenant })
|
|
283
285
|
)
|
|
@@ -751,7 +753,18 @@ class Config {
|
|
|
751
753
|
}
|
|
752
754
|
|
|
753
755
|
get redisOptions() {
|
|
754
|
-
return
|
|
756
|
+
return {
|
|
757
|
+
...this.#redisOptions,
|
|
758
|
+
redisNamespace: `${[REDIS_PREFIX, this.redisNamespace].filter((a) => a).join("_")}`,
|
|
759
|
+
};
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
set redisNamespace(value) {
|
|
763
|
+
this.#redisNamespace = value;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
get redisNamespace() {
|
|
767
|
+
return this.#redisNamespace;
|
|
755
768
|
}
|
|
756
769
|
|
|
757
770
|
set insertEventsBeforeCommit(value) {
|
package/src/initialize.js
CHANGED
package/src/runner/runner.js
CHANGED
|
@@ -18,10 +18,10 @@ const { runEventCombinationForTenant } = require("./runnerHelper");
|
|
|
18
18
|
const { trace } = require("../shared/openTelemetry");
|
|
19
19
|
|
|
20
20
|
const COMPONENT_NAME = "/eventQueue/runner";
|
|
21
|
-
const EVENT_QUEUE_RUN_ID = "
|
|
22
|
-
const EVENT_QUEUE_RUN_TS = "
|
|
23
|
-
const EVENT_QUEUE_RUN_REDIS_CHECK = "
|
|
24
|
-
const EVENT_QUEUE_UPDATE_PERIODIC_EVENTS = "
|
|
21
|
+
const EVENT_QUEUE_RUN_ID = "RUN_ID";
|
|
22
|
+
const EVENT_QUEUE_RUN_TS = "RUN_TS";
|
|
23
|
+
const EVENT_QUEUE_RUN_REDIS_CHECK = "RUN_REDIS_CHECK";
|
|
24
|
+
const EVENT_QUEUE_UPDATE_PERIODIC_EVENTS = "UPDATE_PERIODIC_EVENTS";
|
|
25
25
|
let OFFSET_FIRST_RUN = 10 * 1000;
|
|
26
26
|
|
|
27
27
|
let tenantIdHash;
|
|
@@ -4,7 +4,6 @@ const redis = require("./redis");
|
|
|
4
4
|
const config = require("../config");
|
|
5
5
|
const cdsHelper = require("./cdsHelper");
|
|
6
6
|
|
|
7
|
-
const KEY_PREFIX = "EVENT_QUEUE";
|
|
8
7
|
const existingLocks = {};
|
|
9
8
|
const REDIS_COMMAND_OK = "OK";
|
|
10
9
|
const COMPONENT_NAME = "/eventQueue/distributedLock";
|
|
@@ -176,10 +175,10 @@ const _acquireLockDB = async (context, fullKey, expiryTime, { value = "true", ov
|
|
|
176
175
|
};
|
|
177
176
|
|
|
178
177
|
const _generateKey = (context, tenantScoped, key) => {
|
|
179
|
-
const keyParts = [];
|
|
178
|
+
const keyParts = [config.redisOptions.redisNamespace];
|
|
180
179
|
tenantScoped && keyParts.push(context.tenant);
|
|
181
180
|
keyParts.push(key);
|
|
182
|
-
return `${
|
|
181
|
+
return `${keyParts.join("##")}`;
|
|
183
182
|
};
|
|
184
183
|
|
|
185
184
|
const shutdownHandler = async () => {
|
|
@@ -45,12 +45,6 @@ const trace = async (context, label, fn, { attributes = {}, newRootSpan = false,
|
|
|
45
45
|
|
|
46
46
|
const _startOtelTrace = async (ctxWithSpan, traceContext, span, fn) => {
|
|
47
47
|
return otel.context.with(ctxWithSpan, async () => {
|
|
48
|
-
if (traceContext) {
|
|
49
|
-
cds.log("/eventQueue/telemetry").info("Linked span:", span.spanContext());
|
|
50
|
-
const carrier = {};
|
|
51
|
-
otel.propagation.inject(ctxWithSpan, carrier);
|
|
52
|
-
cds.log("/eventQueue/telemetry").info("Extracted trace context by inject", carrier);
|
|
53
|
-
}
|
|
54
48
|
const onSuccess = (res) => {
|
|
55
49
|
span.setStatus({ code: otel.SpanStatusCode.OK });
|
|
56
50
|
return res;
|
package/src/shared/redis.js
CHANGED
|
@@ -46,6 +46,7 @@ const _createClientBase = (redisOptions = {}) => {
|
|
|
46
46
|
password: redisOptions.password ?? options.password ?? credentials.password,
|
|
47
47
|
socket,
|
|
48
48
|
});
|
|
49
|
+
delete socketOptions.redisNamespace;
|
|
49
50
|
if (credentials.cluster_mode) {
|
|
50
51
|
return redis.createCluster({
|
|
51
52
|
rootNodes: [socketOptions],
|
|
@@ -106,9 +107,10 @@ const _subscribeChannels = (options, subscribedChannels, errorHandlerCreateClien
|
|
|
106
107
|
if (client._subscribedChannels[channel]) {
|
|
107
108
|
continue;
|
|
108
109
|
}
|
|
109
|
-
|
|
110
|
+
const prefixedChannelName = [options.redisNamespace, channel].join("_");
|
|
111
|
+
cds.log(COMPONENT_NAME).info("subscribe redis client connected channel", { channel: prefixedChannelName });
|
|
110
112
|
client
|
|
111
|
-
.subscribe(
|
|
113
|
+
.subscribe(prefixedChannelName, fn)
|
|
112
114
|
.then(() => {
|
|
113
115
|
client._subscribedChannels ??= {};
|
|
114
116
|
client._subscribedChannels[channel] = 1;
|
|
@@ -133,7 +135,7 @@ const _subscribeChannels = (options, subscribedChannels, errorHandlerCreateClien
|
|
|
133
135
|
|
|
134
136
|
const publishMessage = async (options, channel, message) => {
|
|
135
137
|
const client = await createMainClientAndConnect(options);
|
|
136
|
-
return await client.publish(channel, message);
|
|
138
|
+
return await client.publish([options.redisNamespace, channel].join("_"), message);
|
|
137
139
|
};
|
|
138
140
|
|
|
139
141
|
const closeMainClient = async () => {
|