@cap-js-community/event-queue 1.6.3 → 1.6.5

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.3",
3
+ "version": "1.6.5",
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 .",
@@ -63,9 +63,6 @@
63
63
  "prettier": "^2.8.8",
64
64
  "sqlite3": "^5.1.7"
65
65
  },
66
- "peerDependencies": {
67
- "@cap-js/telemetry": "^0.2.2"
68
- },
69
66
  "homepage": "https://cap-js-community.github.io/event-queue/",
70
67
  "repository": {
71
68
  "type": "git",
@@ -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
  )
@@ -920,7 +936,7 @@ class EventQueueProcessorBase {
920
936
  return;
921
937
  }
922
938
  try {
923
- await trace(this.baseContext, "persist-release-lock", async () => {
939
+ await trace(this.baseContext, "release-lock", async () => {
924
940
  await distributedLock.releaseLock(this.context, [this.#eventType, this.#eventSubType].join("##"));
925
941
  });
926
942
  } catch (err) {
@@ -1160,6 +1176,10 @@ class EventQueueProcessorBase {
1160
1176
  get isPeriodicEvent() {
1161
1177
  return this.#eventConfig.isPeriodic;
1162
1178
  }
1179
+
1180
+ get eventConfig() {
1181
+ return this.#eventConfig;
1182
+ }
1163
1183
  }
1164
1184
 
1165
1185
  module.exports = EventQueueProcessorBase;
package/src/config.js CHANGED
@@ -282,6 +282,7 @@ class Config {
282
282
  checkForNextChunk: config.checkForNextChunk,
283
283
  deleteFinishedEventsAfterDays: config.deleteFinishedEventsAfterDays,
284
284
  appNames: config.appNames,
285
+ useEventQueueUser: config.useEventQueueUser,
285
286
  internalEvent: true,
286
287
  };
287
288
  eventConfig._appNameMap = eventConfig.appNames
package/src/index.d.ts CHANGED
@@ -63,6 +63,24 @@ type EventConfigType = {
63
63
  isPeriodic: boolean;
64
64
  };
65
65
 
66
+ export type EventConfig = {
67
+ type: string;
68
+ subType: string;
69
+ load: number;
70
+ impl: string;
71
+ selectMaxChunkSize: number | undefined;
72
+ parallelEventProcessing: boolean;
73
+ retryAttempts: number | undefined;
74
+ transactionMode: string | undefined;
75
+ processAfterCommit: boolean | undefined;
76
+ eventOutdatedCheck: boolean | undefined;
77
+ checkForNextChunk: boolean | undefined;
78
+ deleteFinishedEventsAfterDays: number | undefined;
79
+ appNames: string[] | undefined;
80
+ useEventQueueUser: boolean | undefined;
81
+ internalEvent: true;
82
+ };
83
+
66
84
  // Define Status Type
67
85
  type Status = 0 | 1 | 2 | 3 | 4;
68
86
 
@@ -126,6 +144,7 @@ export declare class EventQueueProcessorBase {
126
144
  get isPeriodicEvent(): boolean;
127
145
  get eventType(): String;
128
146
  get eventSubType(): String;
147
+ get eventConfig(): EventConfig;
129
148
  }
130
149
 
131
150
  export function publishEvent(
@@ -5,6 +5,7 @@ const cds = require("@sap/cds");
5
5
  const EventQueueBaseClass = require("../EventQueueProcessorBase");
6
6
  const { EventProcessingStatus } = require("../constants");
7
7
  const common = require("../shared/common");
8
+ const config = require("../config");
8
9
 
9
10
  const COMPONENT_NAME = "/eventQueue/outbox/generic";
10
11
 
@@ -18,7 +19,8 @@ class EventQueueGenericOutboxHandler extends EventQueueBaseClass {
18
19
  let status = EventProcessingStatus.Done;
19
20
  try {
20
21
  const service = await cds.connect.to(this.eventSubType);
21
- const userId = payload.contextUser;
22
+ const { useEventQueueUser } = this.eventConfig;
23
+ const userId = useEventQueueUser ? config.userId : payload.contextUser;
22
24
  const msg = payload._fromSend ? new cds.Request(payload) : new cds.Event(payload);
23
25
  const invocationFn = payload._fromSend ? "send" : "emit";
24
26
  delete msg._fromSend;