@cap-js-community/event-queue 2.0.4 → 2.1.0-beta.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/package.json +6 -7
- package/src/EventQueueProcessorBase.js +15 -1
- package/src/config.js +34 -3
- package/src/initialize.js +1 -0
- package/src/outbox/EventQueueGenericOutboxHandler.js +64 -11
- package/src/outbox/eventQueueAsOutbox.js +14 -2
- package/src/publishEvent.js +8 -5
- package/src/redis/redisPub.js +5 -3
- package/src/shared/cdsHelper.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cap-js-community/event-queue",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.1.0-beta.0",
|
|
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",
|
|
@@ -56,17 +56,16 @@
|
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@actions/core": "^2.0.2",
|
|
58
58
|
"@cap-js/cds-test": "^0.4.1",
|
|
59
|
-
"@cap-js/db-service": "^2.8.
|
|
60
|
-
"@cap-js/hana": "^2.
|
|
61
|
-
"@cap-js/sqlite": "^2.1.
|
|
59
|
+
"@cap-js/db-service": "^2.8.2",
|
|
60
|
+
"@cap-js/hana": "^2.6.0",
|
|
61
|
+
"@cap-js/sqlite": "^2.1.3",
|
|
62
62
|
"@opentelemetry/api": "^1.9.0",
|
|
63
|
-
"@sap/cds": "^9.
|
|
64
|
-
"@sap/cds-dk": "^9.
|
|
63
|
+
"@sap/cds": "^9.7.0",
|
|
64
|
+
"@sap/cds-dk": "^9.7.0",
|
|
65
65
|
"eslint": "^8.57.1",
|
|
66
66
|
"eslint-config-prettier": "^10.1.8",
|
|
67
67
|
"eslint-plugin-jest": "^29.12.1",
|
|
68
68
|
"eslint-plugin-node": "^11.1.0",
|
|
69
|
-
"express": "^4.22.1",
|
|
70
69
|
"jest": "^29.7.0",
|
|
71
70
|
"prettier": "^2.8.8"
|
|
72
71
|
},
|
|
@@ -25,7 +25,7 @@ const TRIES_FOR_EXCEEDED_EVENTS = 3;
|
|
|
25
25
|
const EVENT_START_AFTER_HEADROOM = 3 * 1000;
|
|
26
26
|
const SUFFIX_PERIODIC = "_PERIODIC";
|
|
27
27
|
|
|
28
|
-
const ALLOWED_FIELDS_FOR_UPDATE = ["status", "startAfter", "error"];
|
|
28
|
+
const ALLOWED_FIELDS_FOR_UPDATE = ["status", "startAfter", "error", "nextData"];
|
|
29
29
|
|
|
30
30
|
class EventQueueProcessorBase {
|
|
31
31
|
#eventsWithExceededTries = [];
|
|
@@ -43,6 +43,7 @@ class EventQueueProcessorBase {
|
|
|
43
43
|
#currentKeepAlivePromise = Promise.resolve();
|
|
44
44
|
#etagMap;
|
|
45
45
|
#namespace;
|
|
46
|
+
#nextSagaEvents;
|
|
46
47
|
|
|
47
48
|
constructor(context, eventType, eventSubType, config) {
|
|
48
49
|
this.__context = context;
|
|
@@ -468,6 +469,10 @@ class EventQueueProcessorBase {
|
|
|
468
469
|
return result;
|
|
469
470
|
}, {});
|
|
470
471
|
|
|
472
|
+
if (!Object.values(updateData).length) {
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
|
|
471
476
|
for (const { ids, data } of Object.values(updateData)) {
|
|
472
477
|
if (!("status" in data)) {
|
|
473
478
|
// TODO: Can this still happen?
|
|
@@ -522,6 +527,11 @@ class EventQueueProcessorBase {
|
|
|
522
527
|
.where("ID IN", ids)
|
|
523
528
|
);
|
|
524
529
|
}
|
|
530
|
+
|
|
531
|
+
if (this.#nextSagaEvents?.length) {
|
|
532
|
+
await tx.run(INSERT.into(this.#config.tableNameEventQueue).entries(this.#nextSagaEvents));
|
|
533
|
+
this.#nextSagaEvents = [];
|
|
534
|
+
}
|
|
525
535
|
});
|
|
526
536
|
}
|
|
527
537
|
|
|
@@ -1390,6 +1400,10 @@ class EventQueueProcessorBase {
|
|
|
1390
1400
|
get allowedFieldsEventHandler() {
|
|
1391
1401
|
return ALLOWED_FIELDS_FOR_UPDATE;
|
|
1392
1402
|
}
|
|
1403
|
+
|
|
1404
|
+
set nextSagaEvents(value) {
|
|
1405
|
+
this.#nextSagaEvents = value;
|
|
1406
|
+
}
|
|
1393
1407
|
}
|
|
1394
1408
|
|
|
1395
1409
|
module.exports = EventQueueProcessorBase;
|
package/src/config.js
CHANGED
|
@@ -28,6 +28,8 @@ const DEFAULT_RETRY_AFTER = 5 * 60 * 1000;
|
|
|
28
28
|
const PRIORITIES = Object.values(Priorities);
|
|
29
29
|
const UTC_DEFAULT = false;
|
|
30
30
|
const USE_CRON_TZ_DEFAULT = true;
|
|
31
|
+
const SAGA_SUCCESS = "#succeeded";
|
|
32
|
+
const SAGA_FAILED = "#failed";
|
|
31
33
|
|
|
32
34
|
const BASE_TABLES = {
|
|
33
35
|
EVENT: "sap.eventqueue.Event",
|
|
@@ -62,6 +64,7 @@ const ALLOWED_EVENT_OPTIONS_AD_HOC = [
|
|
|
62
64
|
"checkForNextChunk",
|
|
63
65
|
"retryFailedAfter",
|
|
64
66
|
"propagateHeaders",
|
|
67
|
+
"propagatedContextProperties",
|
|
65
68
|
"retryOpenAfter",
|
|
66
69
|
"multiInstanceProcessing",
|
|
67
70
|
"kind",
|
|
@@ -236,7 +239,7 @@ class Config {
|
|
|
236
239
|
|
|
237
240
|
executeUnsubscribeHandlers(tenantId) {
|
|
238
241
|
this.#unsubscribedTenants[tenantId] = true;
|
|
239
|
-
setTimeout(() => delete this.#unsubscribedTenants[tenantId], DELETE_TENANT_BLOCK_AFTER_MS);
|
|
242
|
+
setTimeout(() => delete this.#unsubscribedTenants[tenantId], DELETE_TENANT_BLOCK_AFTER_MS).unref();
|
|
240
243
|
for (const unsubscribeHandler of this.#unsubscribeHandlers) {
|
|
241
244
|
try {
|
|
242
245
|
unsubscribeHandler(tenantId);
|
|
@@ -383,6 +386,20 @@ class Config {
|
|
|
383
386
|
result.adHoc
|
|
384
387
|
);
|
|
385
388
|
result.adHoc[key] = specificEventConfig;
|
|
389
|
+
const sagaSuccessKey = [fnName, SAGA_SUCCESS].join("/");
|
|
390
|
+
if (config.events[sagaSuccessKey]) {
|
|
391
|
+
const [sagaKey, sagaSpecificEventConfig] = this.addCAPOutboxEventSpecificAction(
|
|
392
|
+
srvConfig,
|
|
393
|
+
name,
|
|
394
|
+
fnName,
|
|
395
|
+
result.adHoc
|
|
396
|
+
);
|
|
397
|
+
result.adHoc[sagaKey] = sagaSpecificEventConfig;
|
|
398
|
+
} else {
|
|
399
|
+
const sagaConfig = { ...specificEventConfig };
|
|
400
|
+
sagaConfig.subType = [sagaConfig.subType, SAGA_SUCCESS].join("/");
|
|
401
|
+
result.adHoc[[key, SAGA_SUCCESS].join("/")] = sagaConfig;
|
|
402
|
+
}
|
|
386
403
|
}
|
|
387
404
|
}
|
|
388
405
|
return result;
|
|
@@ -405,11 +422,24 @@ class Config {
|
|
|
405
422
|
getCdsOutboxEventSpecificConfig(serviceName, action) {
|
|
406
423
|
const srv = cds.env.requires[serviceName];
|
|
407
424
|
const config = srv?.outbox ?? srv?.queued;
|
|
408
|
-
|
|
425
|
+
const specificConfig = config?.events?.[action];
|
|
426
|
+
|
|
427
|
+
if (specificConfig) {
|
|
409
428
|
return this.#mixCAPPropertyNamesWithEventQueueNames(config.events[action]);
|
|
410
|
-
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
if (!action) {
|
|
411
432
|
return null;
|
|
412
433
|
}
|
|
434
|
+
|
|
435
|
+
const [withoutSaga, sagaSuffix] = action.split("/");
|
|
436
|
+
if ([SAGA_FAILED, SAGA_SUCCESS].includes(sagaSuffix)) {
|
|
437
|
+
if (config?.events?.[withoutSaga]) {
|
|
438
|
+
return this.#mixCAPPropertyNamesWithEventQueueNames(config.events[withoutSaga]);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
return null;
|
|
413
443
|
}
|
|
414
444
|
|
|
415
445
|
#mapEnvEvents(events) {
|
|
@@ -488,6 +518,7 @@ class Config {
|
|
|
488
518
|
? Object.fromEntries(new Map(event.appInstances.map((a) => [a, true])))
|
|
489
519
|
: null;
|
|
490
520
|
event.propagateHeaders = event.propagateHeaders ?? [];
|
|
521
|
+
event.propagatedContextProperties = event.propagatedContextProperties ?? [];
|
|
491
522
|
event.retryFailedAfter = event.retryFailedAfter ?? DEFAULT_RETRY_AFTER;
|
|
492
523
|
event.retryOpenAfter = event.retryOpenAfter ?? DEFAULT_RETRY_AFTER;
|
|
493
524
|
}
|
package/src/initialize.js
CHANGED
|
@@ -14,6 +14,8 @@ const EVENT_QUEUE_ACTIONS = {
|
|
|
14
14
|
EXCEEDED: "eventQueueRetriesExceeded",
|
|
15
15
|
CLUSTER: "eventQueueCluster",
|
|
16
16
|
CHECK_AND_ADJUST: "eventQueueCheckAndAdjustPayload",
|
|
17
|
+
SAGA_SUCCESS: "#succeeded",
|
|
18
|
+
SAGA_FAILED: "#failed",
|
|
17
19
|
};
|
|
18
20
|
|
|
19
21
|
class EventQueueGenericOutboxHandler extends EventQueueBaseClass {
|
|
@@ -25,7 +27,7 @@ class EventQueueGenericOutboxHandler extends EventQueueBaseClass {
|
|
|
25
27
|
async getQueueEntriesAndSetToInProgress() {
|
|
26
28
|
const { srvName } = config.normalizeSubType(this.eventType, this.eventSubType);
|
|
27
29
|
this.__srv = await cds.connect.to(srvName);
|
|
28
|
-
this.__srvUnboxed = cds.
|
|
30
|
+
this.__srvUnboxed = cds.unqueued(this.__srv);
|
|
29
31
|
const { handlers, clusterRelevant, specificClusterRelevant } = this.__srvUnboxed.handlers.on.reduce(
|
|
30
32
|
(result, handler) => {
|
|
31
33
|
if (handler.on.startsWith(EVENT_QUEUE_ACTIONS.CLUSTER)) {
|
|
@@ -260,7 +262,7 @@ class EventQueueGenericOutboxHandler extends EventQueueBaseClass {
|
|
|
260
262
|
async checkEventAndGeneratePayload(queueEntry) {
|
|
261
263
|
const payload = await super.checkEventAndGeneratePayload(queueEntry);
|
|
262
264
|
const { event } = payload;
|
|
263
|
-
const handlerName = this.#checkHandlerExists(EVENT_QUEUE_ACTIONS.CHECK_AND_ADJUST, event);
|
|
265
|
+
const handlerName = this.#checkHandlerExists({ eventQueueFn: EVENT_QUEUE_ACTIONS.CHECK_AND_ADJUST, event });
|
|
264
266
|
if (!handlerName) {
|
|
265
267
|
return payload;
|
|
266
268
|
}
|
|
@@ -281,7 +283,7 @@ class EventQueueGenericOutboxHandler extends EventQueueBaseClass {
|
|
|
281
283
|
|
|
282
284
|
async hookForExceededEvents(exceededEvent) {
|
|
283
285
|
const { event } = exceededEvent.payload;
|
|
284
|
-
const handlerName = this.#checkHandlerExists(EVENT_QUEUE_ACTIONS.EXCEEDED, event);
|
|
286
|
+
const handlerName = this.#checkHandlerExists({ eventQueueFn: EVENT_QUEUE_ACTIONS.EXCEEDED, event });
|
|
285
287
|
if (!handlerName) {
|
|
286
288
|
return await super.hookForExceededEvents(exceededEvent);
|
|
287
289
|
}
|
|
@@ -299,14 +301,23 @@ class EventQueueGenericOutboxHandler extends EventQueueBaseClass {
|
|
|
299
301
|
return await super.beforeProcessingEvents();
|
|
300
302
|
}
|
|
301
303
|
|
|
302
|
-
#checkHandlerExists(eventQueueFn, event) {
|
|
303
|
-
|
|
304
|
+
#checkHandlerExists({ eventQueueFn, event, saga } = {}) {
|
|
305
|
+
if (eventQueueFn) {
|
|
306
|
+
const specificHandler = this.__onHandlers[[eventQueueFn, event].join(".")];
|
|
307
|
+
if (specificHandler) {
|
|
308
|
+
return specificHandler;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const genericHandler = this.__onHandlers[eventQueueFn];
|
|
312
|
+
return genericHandler ?? null;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const specificHandler = this.__onHandlers[[event, saga].join("/")];
|
|
304
316
|
if (specificHandler) {
|
|
305
317
|
return specificHandler;
|
|
306
318
|
}
|
|
307
319
|
|
|
308
|
-
|
|
309
|
-
return genericHandler ?? null;
|
|
320
|
+
return this.__onHandlers[saga];
|
|
310
321
|
}
|
|
311
322
|
|
|
312
323
|
async processPeriodicEvent(processContext, key, queueEntry) {
|
|
@@ -344,7 +355,9 @@ class EventQueueGenericOutboxHandler extends EventQueueBaseClass {
|
|
|
344
355
|
const { userId, invocationFn, reg } = this.#buildDispatchData(processContext, payload, { key, queueEntries });
|
|
345
356
|
await this.#setContextUser(processContext, userId, reg);
|
|
346
357
|
const result = await this.__srvUnboxed.tx(processContext)[invocationFn](reg);
|
|
347
|
-
|
|
358
|
+
const statusTuple = this.#determineResultStatus(result, queueEntries);
|
|
359
|
+
await this.#publishFollowupEvents(processContext, reg, statusTuple);
|
|
360
|
+
return statusTuple;
|
|
348
361
|
} catch (err) {
|
|
349
362
|
this.logger.error("error processing outboxed service call", err, {
|
|
350
363
|
serviceName: this.eventSubType,
|
|
@@ -359,11 +372,51 @@ class EventQueueGenericOutboxHandler extends EventQueueBaseClass {
|
|
|
359
372
|
}
|
|
360
373
|
}
|
|
361
374
|
|
|
375
|
+
async #publishFollowupEvents(processContext, req, statusTuple) {
|
|
376
|
+
const succeeded = this.#checkHandlerExists({ event: req.event, saga: EVENT_QUEUE_ACTIONS.SAGA_SUCCESS });
|
|
377
|
+
const failed = this.#checkHandlerExists({ event: req.event, saga: EVENT_QUEUE_ACTIONS.SAGA_FAILED });
|
|
378
|
+
|
|
379
|
+
if (!succeeded && !failed) {
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
if (req.event.endsWith(EVENT_QUEUE_ACTIONS.SAGA_SUCCESS) || req.event.endsWith(EVENT_QUEUE_ACTIONS.SAGA_FAILED)) {
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// NOTE: required for #failed because tx is rolledback and new events would not be commmited!
|
|
388
|
+
const tx = cds.tx(processContext);
|
|
389
|
+
const nextEvents = tx._eventQueue?.events;
|
|
390
|
+
|
|
391
|
+
if (nextEvents?.length) {
|
|
392
|
+
tx._eventQueue.events = [];
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
for (const [, result] of statusTuple) {
|
|
396
|
+
if (succeeded && result.status === EventProcessingStatus.Done) {
|
|
397
|
+
await this.__srv.tx(processContext).send(succeeded, result.nextData ?? req.data);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
if (failed && result.status === EventProcessingStatus.Error) {
|
|
401
|
+
await this.__srv.tx(processContext).send(failed, result.nextData ?? req.data);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
delete result.nextData;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
if (config.insertEventsBeforeCommit) {
|
|
408
|
+
this.nextSagaEvents = tx._eventQueue.events;
|
|
409
|
+
} else {
|
|
410
|
+
this.nextSagaEvents = tx._eventQueue.events.filter((event) => JSON.parse(event.payload).event === failed);
|
|
411
|
+
}
|
|
412
|
+
tx._eventQueue.events = nextEvents ?? [];
|
|
413
|
+
}
|
|
414
|
+
|
|
362
415
|
#determineResultStatus(result, queueEntries) {
|
|
363
416
|
const validStatusValues = Object.values(EventProcessingStatus);
|
|
364
417
|
const validStatus = validStatusValues.includes(result);
|
|
365
418
|
if (validStatus) {
|
|
366
|
-
return queueEntries.map((queueEntry) => [queueEntry.ID, result]);
|
|
419
|
+
return queueEntries.map((queueEntry) => [queueEntry.ID, { status: result }]);
|
|
367
420
|
}
|
|
368
421
|
|
|
369
422
|
if (result instanceof Object && !Array.isArray(result)) {
|
|
@@ -375,7 +428,7 @@ class EventQueueGenericOutboxHandler extends EventQueueBaseClass {
|
|
|
375
428
|
}
|
|
376
429
|
|
|
377
430
|
if (!Array.isArray(result)) {
|
|
378
|
-
return queueEntries.map((queueEntry) => [queueEntry.ID, EventProcessingStatus.Done]);
|
|
431
|
+
return queueEntries.map((queueEntry) => [queueEntry.ID, { status: EventProcessingStatus.Done }]);
|
|
379
432
|
}
|
|
380
433
|
|
|
381
434
|
const [firstEntry] = result;
|
|
@@ -430,7 +483,7 @@ class EventQueueGenericOutboxHandler extends EventQueueBaseClass {
|
|
|
430
483
|
if (valid) {
|
|
431
484
|
return result;
|
|
432
485
|
} else {
|
|
433
|
-
return queueEntries.map((queueEntry) => [queueEntry.ID, EventProcessingStatus.Done]);
|
|
486
|
+
return queueEntries.map((queueEntry) => [queueEntry.ID, { status: EventProcessingStatus.Done }]);
|
|
434
487
|
}
|
|
435
488
|
}
|
|
436
489
|
}
|
|
@@ -43,8 +43,9 @@ function outboxed(srv, customOpts) {
|
|
|
43
43
|
|
|
44
44
|
const outboxOpts = config.getEventConfig(CDS_EVENT_TYPE, subType, srvConfig.namespace);
|
|
45
45
|
const eventHeaders = getPropagatedHeaders(outboxOpts, req);
|
|
46
|
+
const contextProperties = getPropagatedContextProperties(outboxOpts, req);
|
|
46
47
|
if (["persistent-outbox", "persistent-queue"].includes(outboxOpts.kind)) {
|
|
47
|
-
await _mapToEventAndPublish(
|
|
48
|
+
await _mapToEventAndPublish(req, srvConfig.namespace, subType, eventHeaders, contextProperties);
|
|
48
49
|
return;
|
|
49
50
|
}
|
|
50
51
|
context.on("succeeded", async () => {
|
|
@@ -80,7 +81,17 @@ const getPropagatedHeaders = (config, req) => {
|
|
|
80
81
|
return Object.assign(propagateHeaders, req.headers);
|
|
81
82
|
};
|
|
82
83
|
|
|
83
|
-
const
|
|
84
|
+
const getPropagatedContextProperties = (config, req) => {
|
|
85
|
+
return config.propagatedContextProperties.reduce((properties, name) => {
|
|
86
|
+
if (name in req.tx.context) {
|
|
87
|
+
properties[name] = req.tx.context[name];
|
|
88
|
+
}
|
|
89
|
+
return properties;
|
|
90
|
+
}, {});
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const _mapToEventAndPublish = async (req, namespace, subType, eventHeaders, contextProperties) => {
|
|
94
|
+
const context = req.context || cds.context;
|
|
84
95
|
const eventQueueSpecificValues = {};
|
|
85
96
|
for (const header in req.headers ?? {}) {
|
|
86
97
|
for (const field of EVENT_QUEUE_SPECIFIC_FIELDS) {
|
|
@@ -100,6 +111,7 @@ const _mapToEventAndPublish = async (context, subType, req, eventHeaders, namesp
|
|
|
100
111
|
...(req.data && { data: req.data }),
|
|
101
112
|
...(eventHeaders && { headers: eventHeaders }),
|
|
102
113
|
...(req.query && { query: req.query }),
|
|
114
|
+
...(Object.keys(contextProperties).length && { ...contextProperties }),
|
|
103
115
|
};
|
|
104
116
|
|
|
105
117
|
await publishEvent(
|
package/src/publishEvent.js
CHANGED
|
@@ -76,8 +76,9 @@ const publishEvent = async (
|
|
|
76
76
|
event.namespace = config.namespace;
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
|
+
_addEventsToContext(tx, events);
|
|
79
80
|
if (config.insertEventsBeforeCommit && !skipInsertEventsBeforeCommit) {
|
|
80
|
-
|
|
81
|
+
_registerHandler(tx, skipBroadcast);
|
|
81
82
|
} else {
|
|
82
83
|
let result;
|
|
83
84
|
tx._skipEventQueueBroadcast = skipBroadcast;
|
|
@@ -87,10 +88,7 @@ const publishEvent = async (
|
|
|
87
88
|
}
|
|
88
89
|
};
|
|
89
90
|
|
|
90
|
-
const
|
|
91
|
-
tx._eventQueue ??= { events: [], handlerRegistered: false };
|
|
92
|
-
tx._eventQueue.events = tx._eventQueue.events.concat(events);
|
|
93
|
-
|
|
91
|
+
const _registerHandler = (tx, skipBroadcast) => {
|
|
94
92
|
if (tx._eventQueue.handlerRegistered) {
|
|
95
93
|
return;
|
|
96
94
|
}
|
|
@@ -106,6 +104,11 @@ const _registerHandlerAndAddEvents = (tx, events, skipBroadcast) => {
|
|
|
106
104
|
});
|
|
107
105
|
};
|
|
108
106
|
|
|
107
|
+
const _addEventsToContext = (tx, events) => {
|
|
108
|
+
tx._eventQueue ??= { events: [], handlerRegistered: false };
|
|
109
|
+
tx._eventQueue.events = tx._eventQueue.events.concat(events);
|
|
110
|
+
};
|
|
111
|
+
|
|
109
112
|
module.exports = {
|
|
110
113
|
publishEvent,
|
|
111
114
|
};
|
package/src/redis/redisPub.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
const { promisify } = require("util");
|
|
4
|
-
|
|
5
3
|
const cds = require("@sap/cds");
|
|
6
4
|
|
|
7
5
|
const redis = require("../shared/redis");
|
|
@@ -17,7 +15,11 @@ const COMPONENT_NAME = "/eventQueue/redisPub";
|
|
|
17
15
|
const TRIES_FOR_PUBLISH_PERIODIC_EVENT = 10;
|
|
18
16
|
const SLEEP_TIME_FOR_PUBLISH_PERIODIC_EVENT = 30 * 1000;
|
|
19
17
|
|
|
20
|
-
const wait =
|
|
18
|
+
const wait = async (ms) => {
|
|
19
|
+
return new Promise((resolve) => {
|
|
20
|
+
setTimeout(resolve, ms).unref();
|
|
21
|
+
});
|
|
22
|
+
};
|
|
21
23
|
|
|
22
24
|
/**
|
|
23
25
|
* Broadcasts events to the event queue, either locally or through Redis.
|
package/src/shared/cdsHelper.js
CHANGED
|
@@ -130,7 +130,7 @@ const _getAllTenantBase = async () => {
|
|
|
130
130
|
if (cds.services["cds.xt.SaasProvisioningService"] || cds.services["saas-registry"]) {
|
|
131
131
|
break;
|
|
132
132
|
}
|
|
133
|
-
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
133
|
+
await new Promise((resolve) => setTimeout(resolve, 1000).unref());
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
const ssp = await cds.connect.to("cds.xt.SaasProvisioningService");
|