@cap-js-community/event-queue 1.6.4 → 1.6.6

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cap-js-community/event-queue",
3
- "version": "1.6.4",
3
+ "version": "1.6.6",
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",
@@ -27,7 +27,7 @@
27
27
  "test:all:coverage": "jest --runInBand --forceExit --collect-coverage",
28
28
  "test:prepare": "npm run build:ci --prefix=./test-integration/_env",
29
29
  "test:deploySchema": "node test-integration/_env/srv/hana/deploy.js",
30
- "test:cleanSchemas": "node test-integration/_env/srv/hana/cleanObsoletSchemas.js",
30
+ "test:cleanSchemas": "node test-integration/_env/srv/hana/deleteTestSchema.js ",
31
31
  "lint": "npm run eslint && npm run prettier",
32
32
  "lint:ci": "npm run eslint:ci && npm run prettier:ci",
33
33
  "eslint": "eslint --fix .",
@@ -24,6 +24,7 @@ const TRIES_FOR_EXCEEDED_EVENTS = 3;
24
24
  const EVENT_START_AFTER_HEADROOM = 3 * 1000;
25
25
  const ETAG_CHECK_AFTER_MIN = 10;
26
26
  const SUFFIX_PERIODIC = "_PERIODIC";
27
+ const DEFAULT_RETRY_AFTER = 5 * 60 * 1000;
27
28
 
28
29
  class EventQueueProcessorBase {
29
30
  #eventsWithExceededTries = [];
@@ -37,6 +38,7 @@ class EventQueueProcessorBase {
37
38
  #eventConfig;
38
39
  #isPeriodic;
39
40
  #lastSuccessfulRunTimestamp;
41
+ #retryFailedAfter;
40
42
 
41
43
  constructor(context, eventType, eventSubType, config) {
42
44
  this.__context = context;
@@ -57,6 +59,7 @@ class EventQueueProcessorBase {
57
59
  if (this.__parallelEventProcessing > LIMIT_PARALLEL_EVENT_PROCESSING) {
58
60
  this.__parallelEventProcessing = LIMIT_PARALLEL_EVENT_PROCESSING;
59
61
  }
62
+ this.#retryFailedAfter = this.#eventConfig.retryFailedAfter ?? DEFAULT_RETRY_AFTER;
60
63
  // NOTE: keep the feature, this might be needed again
61
64
  this.__concurrentEventProcessing = false;
62
65
  this.__startTime = this.#eventConfig.startTime ?? new Date();
@@ -454,11 +457,23 @@ class EventQueueProcessorBase {
454
457
  if (!eventIds.length) {
455
458
  continue;
456
459
  }
460
+ let startAfter;
461
+ if (status === EventProcessingStatus.Error) {
462
+ startAfter = new Date(Date.now() + this.#retryFailedAfter);
463
+ this.#eventSchedulerInstance.scheduleEvent(
464
+ this.__context.tenant,
465
+ this.#eventType,
466
+ this.#eventSubType,
467
+ startAfter
468
+ );
469
+ }
470
+
457
471
  await tx.run(
458
472
  UPDATE.entity(this.#config.tableNameEventQueue)
459
473
  .set({
460
474
  status: status,
461
475
  lastAttemptTimestamp: ts,
476
+ ...(status === EventProcessingStatus.Error ? { startAfter: startAfter.toISOString() } : {}),
462
477
  })
463
478
  .where("ID IN", eventIds)
464
479
  );
@@ -552,7 +567,8 @@ class EventQueueProcessorBase {
552
567
  */
553
568
  async getQueueEntriesAndSetToInProgress() {
554
569
  let result = [];
555
- const refDateStartAfter = new Date(Date.now() + this.#config.runInterval * 1.2);
570
+ const baseDate = Date.now();
571
+ const refDateStartAfter = new Date(baseDate + this.#config.runInterval * 1.2);
556
572
  await executeInNewTransaction(this.__baseContext, "eventQueue-getQueueEntriesAndSetToInProgress", async (tx) => {
557
573
  const entries = await tx.run(
558
574
  SELECT.from(this.#config.tableNameEventQueue)
@@ -574,7 +590,7 @@ class EventQueueProcessorBase {
574
590
  "OR lastAttemptTimestamp IS NULL ) OR ( status =",
575
591
  EventProcessingStatus.InProgress,
576
592
  "AND lastAttemptTimestamp <=",
577
- new Date(new Date().getTime() - this.#config.globalTxTimeout).toISOString(),
593
+ new Date(baseDate - this.#config.globalTxTimeout).toISOString(),
578
594
  ") )",
579
595
  ]
580
596
  : [
@@ -585,7 +601,7 @@ class EventQueueProcessorBase {
585
601
  ") OR ( status =",
586
602
  EventProcessingStatus.InProgress,
587
603
  "AND lastAttemptTimestamp <=",
588
- new Date(new Date().getTime() - this.#config.globalTxTimeout).toISOString(),
604
+ new Date(baseDate - this.#config.globalTxTimeout).toISOString(),
589
605
  ") )",
590
606
  ])
591
607
  )
@@ -142,7 +142,8 @@ const _executeEventsAllTenantsRedis = async (tenantIds) => {
142
142
  if (!entries.length) {
143
143
  return;
144
144
  }
145
- await redisPub.broadcastEvent(tenantId, entries).catch((err) => {
145
+ // Do not wait until this is finished - as broadcastEvent has a retry mechanism and can delay this loop
146
+ redisPub.broadcastEvent(tenantId, entries).catch((err) => {
146
147
  logger.error("broadcasting event failed", err, {
147
148
  tenantId,
148
149
  entries: entries.length,