@cap-js-community/event-queue 1.10.1 → 1.10.3

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.10.1",
3
+ "version": "1.10.3",
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",
@@ -1019,11 +1019,18 @@ class EventQueueProcessorBase {
1019
1019
  async scheduleNextPeriodEvent(queueEntry) {
1020
1020
  const intervalInMs = this.#eventConfig.cron ? null : this.#eventConfig.interval * 1000;
1021
1021
  const next = this.#calculateCronDates();
1022
+ let newStartAfter;
1023
+
1024
+ if (this.#eventConfig.cron) {
1025
+ newStartAfter = next.getTime() + this.#calculateRandomOffset();
1026
+ } else {
1027
+ newStartAfter = new Date(queueEntry.startAfter).getTime() + intervalInMs + this.#calculateRandomOffset();
1028
+ }
1022
1029
 
1023
1030
  const newEvent = {
1024
1031
  type: this.#eventType,
1025
1032
  subType: this.#eventSubType,
1026
- startAfter: next ?? new Date(new Date(queueEntry.startAfter).getTime() + intervalInMs),
1033
+ startAfter: new Date(newStartAfter),
1027
1034
  };
1028
1035
  const { relative } = this.#eventSchedulerInstance.calculateOffset(
1029
1036
  this.#eventType,
@@ -1071,6 +1078,15 @@ class EventQueueProcessorBase {
1071
1078
  }
1072
1079
  }
1073
1080
 
1081
+ #calculateRandomOffset() {
1082
+ const offset = this.#eventConfig.randomOffset ?? this.#config.randomOffsetPeriodicEvents;
1083
+ if (!offset) {
1084
+ return 0;
1085
+ }
1086
+
1087
+ return Math.floor(Math.random() * offset) * 1000;
1088
+ }
1089
+
1074
1090
  async handleDuplicatedPeriodicEventEntry(queueEntries) {
1075
1091
  this.logger.error("More than one open events for the same configuration which is not allowed!", {
1076
1092
  eventType: this.#eventType,
package/src/config.js CHANGED
@@ -75,6 +75,7 @@ const ALLOWED_EVENT_OPTIONS_PERIODIC_EVENT = [
75
75
  "cron",
76
76
  "utc",
77
77
  "useCronTimezone",
78
+ "randomOffset",
78
79
  ];
79
80
 
80
81
  class Config {
@@ -108,6 +109,7 @@ class Config {
108
109
  #unsubscribeHandlers = [];
109
110
  #unsubscribedTenants = {};
110
111
  #cronTimezone;
112
+ #randomOffsetPeriodicEvents;
111
113
  #redisNamespace;
112
114
  #publishEventBlockList;
113
115
  #crashOnRedisUnavailable;
@@ -167,7 +169,15 @@ class Config {
167
169
  return { type: "string", value: str };
168
170
  }
169
171
 
170
- shouldBeProcessedInThisApplication(type, subType) {
172
+ #normalizeSubType(rawSubType) {
173
+ const [serviceName, actionName] = rawSubType.split(".");
174
+ const actionSpecificCall = this.getCdsOutboxEventSpecificConfig(serviceName, actionName);
175
+ return actionSpecificCall ? rawSubType : serviceName;
176
+ }
177
+
178
+ shouldBeProcessedInThisApplication(type, rawSubType) {
179
+ const subType = this.#normalizeSubType(rawSubType);
180
+
171
181
  const config = this.#eventMap[this.generateKey(type, subType)];
172
182
  const appNameConfig = config._appNameMap;
173
183
  const appInstanceConfig = config._appInstancesMap;
@@ -815,6 +825,14 @@ class Config {
815
825
  this.#cronTimezone = value;
816
826
  }
817
827
 
828
+ get randomOffsetPeriodicEvents() {
829
+ return this.#randomOffsetPeriodicEvents;
830
+ }
831
+
832
+ set randomOffsetPeriodicEvents(value) {
833
+ this.#randomOffsetPeriodicEvents = value;
834
+ }
835
+
818
836
  get instanceLoadLimit() {
819
837
  return this.#instanceLoadLimit;
820
838
  }
package/src/initialize.js CHANGED
@@ -42,6 +42,7 @@ const CONFIG_VARS = [
42
42
  ["insertEventsBeforeCommit", true],
43
43
  ["enableTelemetry", true],
44
44
  ["cronTimezone", null],
45
+ ["randomOffsetPeriodicEvents", null],
45
46
  ["redisNamespace", null],
46
47
  ["publishEventBlockList", true],
47
48
  ["crashOnRedisUnavailable", false],
@@ -68,6 +69,7 @@ const CONFIG_VARS = [
68
69
  * @param {boolean} [options.insertEventsBeforeCommit=true] - Insert events into the queue before committing the transaction.
69
70
  * @param {boolean} [options.enableTelemetry=false] - Enable telemetry for CAP.
70
71
  * @param {string} [options.cronTimezone=null] - Default timezone for cron jobs.
72
+ * @param {string} [options.randomOffsetPeriodicEvents=null] - Default random offset for periodic events.
71
73
  * @param {string} [options.publishEventBlockList=true] - If redis is available event blocklist is distributed to all application instances
72
74
  * @param {string} [options.crashOnRedisUnavailable=true] - If enabled an error is thrown if the redis connection check is not successful
73
75
  */
@@ -47,7 +47,6 @@ function outboxed(srv, customOpts) {
47
47
  customOpts || {}
48
48
  );
49
49
  config.addCAPOutboxEventBase(srv.name, outboxOpts);
50
- // TODO: check req.event ?? req.method
51
50
  const specificSettings = config.getCdsOutboxEventSpecificConfig(srv.name, req.event);
52
51
  if (specificSettings) {
53
52
  outboxOpts = config.addCAPOutboxEventSpecificAction(srv.name, req.event);
@@ -40,11 +40,18 @@ const _messageHandlerProcessEvents = async (messageData) => {
40
40
  return;
41
41
  }
42
42
 
43
+ const [serviceNameOrSubType, actionName] = subType.split(".");
43
44
  if (!config.getEventConfig(type, subType)) {
44
45
  if (config.isCapOutboxEvent(type)) {
45
46
  try {
46
- const service = await cds.connect.to(subType);
47
+ const service = await cds.connect.to(serviceNameOrSubType);
47
48
  cds.outboxed(service);
49
+ if (actionName) {
50
+ const specificSettings = config.getCdsOutboxEventSpecificConfig(serviceNameOrSubType, actionName);
51
+ if (specificSettings) {
52
+ config.addCAPOutboxEventSpecificAction(serviceNameOrSubType, actionName);
53
+ }
54
+ }
48
55
  } catch (err) {
49
56
  logger.warn("could not connect to outboxed service", err, {
50
57
  type,