@cap-js-community/event-queue 1.6.0 → 1.6.2

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.0",
3
+ "version": "1.6.2",
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",
@@ -43,16 +43,16 @@
43
43
  "node": ">=18"
44
44
  },
45
45
  "dependencies": {
46
- "@sap/xssec": "^3.6.1",
47
- "redis": "^4.6.15",
46
+ "@sap/xssec": "^4.2.1",
47
+ "redis": "^4.7.0",
48
48
  "verror": "^1.10.1",
49
- "yaml": "^2.4.2"
49
+ "yaml": "^2.5.0"
50
50
  },
51
51
  "devDependencies": {
52
- "@cap-js/hana": "^1.1.0",
53
- "@cap-js/sqlite": "^1.7.2",
54
- "@sap/cds": "^7.9.2",
55
- "@sap/cds-dk": "^7.8.0",
52
+ "@cap-js/hana": "^1.1.1",
53
+ "@cap-js/sqlite": "^1.7.3",
54
+ "@sap/cds": "^8.1.0",
55
+ "@sap/cds-dk": "^8.1.0",
56
56
  "eslint": "^8.57.0",
57
57
  "eslint-config-prettier": "^9.1.0",
58
58
  "eslint-plugin-jest": "^28.6.0",
@@ -163,12 +163,13 @@ class EventQueueProcessorBase {
163
163
  );
164
164
  }
165
165
 
166
- logTimeExceeded(iterationCounter) {
167
- this.logger.info("Exiting event queue processing as max time exceeded", {
166
+ logTimeExceededAndPublishContinue(iterationCounter) {
167
+ this.logger.info("Exiting event queue processing as max time exceeded - but broadcast to trigger processing", {
168
168
  eventType: this.#eventType,
169
169
  eventSubType: this.#eventSubType,
170
170
  iterationCounter,
171
171
  });
172
+ this.#eventSchedulerInstance.scheduleEvent(this.__context.tenant, this.#eventType, this.#eventSubType, new Date());
172
173
  }
173
174
 
174
175
  logStartMessage() {
package/src/index.d.ts CHANGED
@@ -117,6 +117,7 @@ export declare class EventQueueProcessorBase {
117
117
  setShouldRollbackTransaction(key: string): void;
118
118
  shouldRollbackTransaction(key: string): boolean;
119
119
  beforeProcessingEvents(): Promise<void>;
120
+ addEntryToProcessingMap(key: string, queueEntry: EventEntity, payload: Object): void;
120
121
 
121
122
  set logger(value: CdsLogger);
122
123
  get logger(): CdsLogger;
@@ -214,3 +215,38 @@ declare class Config {
214
215
  }
215
216
 
216
217
  export const config: Config;
218
+
219
+ export const workerQueue: WorkerQueue;
220
+
221
+ declare class WorkerQueue {
222
+ constructor(concurrency: number);
223
+
224
+ addToQueue(load: number, label: string, priority?: Priorities, cb?: () => any): Promise<any>;
225
+
226
+ _executeFunction(
227
+ load: number,
228
+ label: string,
229
+ cb: () => any,
230
+ resolve: (value?: unknown) => void,
231
+ reject: (reason?: any) => void,
232
+ startTime: bigint,
233
+ priority: string
234
+ ): void;
235
+
236
+ get runningPromises(): Array<Promise<any>>;
237
+ get runningLoad(): number;
238
+
239
+ static get instance(): WorkerQueue;
240
+
241
+ get queue(): Record<
242
+ string,
243
+ Array<[number, string, () => any, (value?: unknown) => void, (reason?: any) => void, bigint]>
244
+ >;
245
+ }
246
+
247
+ interface Priorities {
248
+ Low: string;
249
+ Medium: string;
250
+ High: string;
251
+ VeryHigh: string;
252
+ }
package/src/index.js CHANGED
@@ -10,4 +10,5 @@ module.exports = {
10
10
  ...require("./constants"),
11
11
  ...require("./publishEvent"),
12
12
  EventQueueProcessorBase: require("./EventQueueProcessorBase"),
13
+ WorkerQueue: require("./shared/WorkerQueue"),
13
14
  };
@@ -120,7 +120,7 @@ const reevaluateShouldContinue = (eventTypeInstance, iterationCounter, startTime
120
120
  return true;
121
121
  }
122
122
 
123
- eventTypeInstance.logTimeExceeded(iterationCounter);
123
+ eventTypeInstance.logTimeExceededAndPublishContinue(iterationCounter);
124
124
  return false;
125
125
  };
126
126
 
@@ -8,7 +8,7 @@ const { Priorities } = require("../constants");
8
8
  const SetIntervalDriftSafe = require("./SetIntervalDriftSafe");
9
9
 
10
10
  const PRIORITIES = Object.values(Priorities).reverse();
11
- const PRIORITY_MULTIPLICATOR = PRIORITIES.reduce((result, element, index) => {
11
+ const PRIORITY_MULTIPLICATION = PRIORITIES.reduce((result, element, index) => {
12
12
  result[element] = index + 1;
13
13
  return result;
14
14
  }, {});
@@ -152,6 +152,10 @@ class WorkerQueue {
152
152
  return this.#queue;
153
153
  }
154
154
 
155
+ get runningLoad() {
156
+ return this.#runningLoad;
157
+ }
158
+
155
159
  #checkAndLogWaitingTime(startTime, label, priority) {
156
160
  const ts = Date.now();
157
161
  if (ts - lastLogTs <= 1000) {
@@ -159,7 +163,7 @@ class WorkerQueue {
159
163
  }
160
164
  lastLogTs = ts;
161
165
  const diffMs = Math.round(Number(process.hrtime.bigint() - startTime) / NANO_TO_MS);
162
- const priorityMultiplication = PRIORITY_MULTIPLICATOR[priority];
166
+ const priorityMultiplication = PRIORITY_MULTIPLICATION[priority];
163
167
  let logLevel;
164
168
  if (diffMs >= THRESHOLD.ERROR * priorityMultiplication) {
165
169
  logLevel = "error";
@@ -1,15 +1,10 @@
1
1
  "use strict";
2
2
 
3
3
  const crypto = require("crypto");
4
- const { promisify } = require("util");
5
4
 
6
5
  const cds = require("@sap/cds");
7
6
  const xssec = require("@sap/xssec");
8
7
 
9
- const getAuthTokenAsync = promisify(xssec.requests.requestClientCredentialsToken);
10
- const getCreateSecurityContextAsync = promisify(xssec.createSecurityContext);
11
-
12
- let authInfoCache = {};
13
8
  const MARGIN_AUTH_INFO_EXPIRY = 60 * 1000;
14
9
  const COMPONENT_NAME = "/eventQueue/common";
15
10
 
@@ -74,9 +69,15 @@ const processChunkedSync = (inputs, chunkSize, chunkHandler) => {
74
69
  const hashStringTo32Bit = (value) => crypto.createHash("sha256").update(String(value)).digest("base64").slice(0, 32);
75
70
 
76
71
  const _getNewAuthInfo = async (tenantId) => {
72
+ const authInfoCache = getAuthInfo._authInfoCache;
73
+ authInfoCache[tenantId] = authInfoCache[tenantId] ?? {};
77
74
  try {
78
- const token = await getAuthTokenAsync(null, cds.requires.auth.credentials, null, tenantId);
79
- const authInfo = await getCreateSecurityContextAsync(token, cds.requires.auth.credentials);
75
+ if (!_getNewAuthInfo._xsuaaService) {
76
+ _getNewAuthInfo._xsuaaService = new xssec.XsuaaService(cds.requires.auth.credentials);
77
+ }
78
+ const authService = _getNewAuthInfo._xsuaaService;
79
+ const token = await authService.fetchClientCredentialsToken({ zid: tenantId });
80
+ const authInfo = await authService.createSecurityContext(token.access_token);
80
81
  authInfoCache[tenantId].expireTs = authInfo.getExpirationDate().getTime() - MARGIN_AUTH_INFO_EXPIRY;
81
82
  return authInfo;
82
83
  } catch (err) {
@@ -89,7 +90,13 @@ const getAuthInfo = async (tenantId) => {
89
90
  if (!cds.requires?.auth?.credentials) {
90
91
  return null; // no credentials not authInfo
91
92
  }
93
+ if (!cds.requires?.auth.kind.match(/jwt|xsuaa/i)) {
94
+ cds.log(COMPONENT_NAME).warn("Only 'jwt' or 'xsuaa' are supported as values for auth.kind.");
95
+ return null;
96
+ }
92
97
 
98
+ getAuthInfo._authInfoCache = getAuthInfo._authInfoCache ?? {};
99
+ const authInfoCache = getAuthInfo._authInfoCache;
93
100
  // not existing or existing but expired
94
101
  if (
95
102
  !authInfoCache[tenantId] ||
@@ -110,6 +117,6 @@ module.exports = {
110
117
  hashStringTo32Bit,
111
118
  getAuthInfo,
112
119
  __: {
113
- clearAuthInfoCache: () => (authInfoCache = {}),
120
+ clearAuthInfoCache: () => (getAuthInfo._authInfoCache = {}),
114
121
  },
115
122
  };