@cap-js-community/event-queue 1.2.3 → 1.2.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/README.md CHANGED
@@ -28,7 +28,6 @@ For detailed information check out the [documentation](https://cap-js-community.
28
28
  {
29
29
  "cds": {
30
30
  "eventQueue": {
31
- "plugin": true,
32
31
  "configFilePath": "./srv/eventQueueConfig.yml"
33
32
  }
34
33
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cap-js-community/event-queue",
3
- "version": "1.2.3",
4
- "description": "An event queue that enables secure transactional processing of asynchronous events, featuring instant event processing with Redis Pub/Sub and load distribution across all application instances.",
3
+ "version": "1.2.5",
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
  "files": [
7
7
  "src",
@@ -49,15 +49,15 @@
49
49
  "devDependencies": {
50
50
  "@sap/cds": "^7.5.3",
51
51
  "@sap/cds-dk": "^7.5.1",
52
- "eslint": "8.56.0",
53
- "eslint-config-prettier": "9.1.0",
54
- "eslint-plugin-jest": "27.6.3",
55
- "eslint-plugin-node": "11.1.0",
56
- "express": "4.18.2",
57
- "hdb": "0.19.7",
58
- "jest": "29.7.0",
59
- "prettier": "2.8.8",
60
- "sqlite3": "5.1.7"
52
+ "eslint": "^8.56.0",
53
+ "eslint-config-prettier": "^9.1.0",
54
+ "eslint-plugin-jest": "^27.6.3",
55
+ "eslint-plugin-node": "^11.1.0",
56
+ "express": "^4.18.2",
57
+ "hdb": "^0.19.7",
58
+ "jest": "^29.7.0",
59
+ "prettier": "^2.8.8",
60
+ "sqlite3": "^5.1.7"
61
61
  },
62
62
  "homepage": "https://cap-js-community.github.io/event-queue/",
63
63
  "repository": {
@@ -21,7 +21,7 @@ const SELECT_LIMIT_EVENTS_PER_TICK = 100;
21
21
  const TRIES_FOR_EXCEEDED_EVENTS = 3;
22
22
  const EVENT_START_AFTER_HEADROOM = 3 * 1000;
23
23
 
24
- let serviceBindingCache = {};
24
+ let serviceBindingCache = null;
25
25
 
26
26
  class EventQueueProcessorBase {
27
27
  #eventsWithExceededTries = [];
@@ -700,13 +700,16 @@ class EventQueueProcessorBase {
700
700
  }
701
701
 
702
702
  async #getServiceBindings() {
703
- if (serviceBindingCache && serviceBindingCache.exipreTs >= Date.now()) {
704
- return serviceBindingCache.value;
703
+ if (!(serviceBindingCache && serviceBindingCache.expireTs >= Date.now())) {
704
+ const mtxServiceManager = require("@sap/cds-mtxs/srv/plugins/hana/srv-mgr");
705
+ serviceBindingCache = {
706
+ expireTs: Date.now() + 10 * 60 * 1000,
707
+ value: mtxServiceManager.getAll().catch(() => {
708
+ serviceBindingCache = null;
709
+ }),
710
+ };
705
711
  }
706
- const mtxServiceManager = require("@sap/cds-mtxs/srv/plugins/hana/srv-mgr");
707
- serviceBindingCache.value = await mtxServiceManager.getAll();
708
- serviceBindingCache.exipreTs = Date.now() + 10 * 60 * 1000;
709
- return serviceBindingCache.value;
712
+ return await serviceBindingCache.value;
710
713
  }
711
714
 
712
715
  async #selectLastSuccessfulPeriodicTimestamp() {
package/src/config.js CHANGED
@@ -57,6 +57,7 @@ class Config {
57
57
  #useAsCAPOutbox;
58
58
  #userId;
59
59
  #enableTxConsistencyCheck;
60
+ #cleanupLocksAndEventsForDev;
60
61
  static #instance;
61
62
  constructor() {
62
63
  this.#logger = cds.log(COMPONENT_NAME);
@@ -340,6 +341,9 @@ class Config {
340
341
  }
341
342
 
342
343
  set runInterval(value) {
344
+ if (!Number.isInteger(value) || value <= 10 * 1000) {
345
+ throw EventQueueError.invalidInterval();
346
+ }
343
347
  this.#runInterval = value;
344
348
  }
345
349
 
@@ -471,6 +475,14 @@ class Config {
471
475
  return this.#enableTxConsistencyCheck;
472
476
  }
473
477
 
478
+ set cleanupLocksAndEventsForDev(value) {
479
+ this.#cleanupLocksAndEventsForDev = value;
480
+ }
481
+
482
+ get cleanupLocksAndEventsForDev() {
483
+ return this.#cleanupLocksAndEventsForDev;
484
+ }
485
+
474
486
  get isMultiTenancy() {
475
487
  return !!cds.requires.multitenancy;
476
488
  }
package/src/initialize.js CHANGED
@@ -14,6 +14,8 @@ const config = require("./config");
14
14
  const { initEventQueueRedisSubscribe, closeSubscribeClient } = require("./redisPubSub");
15
15
  const { closeMainClient } = require("./shared/redis");
16
16
  const eventQueueAsOutbox = require("./outbox/eventQueueAsOutbox");
17
+ const { getAllTenantIds } = require("./shared/cdsHelper");
18
+ const { EventProcessingStatus } = require("./constants");
17
19
 
18
20
  const readFileAsync = promisify(fs.readFile);
19
21
 
@@ -38,6 +40,7 @@ const CONFIG_VARS = [
38
40
  ["useAsCAPOutbox", false],
39
41
  ["userId", null],
40
42
  ["enableTxConsistencyCheck", false],
43
+ ["registerCleanupForDev", true],
41
44
  ];
42
45
 
43
46
  const initialize = async ({
@@ -55,11 +58,8 @@ const initialize = async ({
55
58
  useAsCAPOutbox,
56
59
  userId,
57
60
  enableTxConsistencyCheck,
61
+ cleanupLocksAndEventsForDev,
58
62
  } = {}) => {
59
- // TODO: initialize check:
60
- // - content of yaml check
61
- // - betweenRuns
62
-
63
63
  if (config.initialized) {
64
64
  return;
65
65
  }
@@ -79,7 +79,8 @@ const initialize = async ({
79
79
  thresholdLoggingEventProcessing,
80
80
  useAsCAPOutbox,
81
81
  userId,
82
- enableTxConsistencyCheck
82
+ enableTxConsistencyCheck,
83
+ cleanupLocksAndEventsForDev
83
84
  );
84
85
 
85
86
  const logger = cds.log(COMPONENT);
@@ -90,6 +91,7 @@ const initialize = async ({
90
91
  cds.on("connect", (service) => {
91
92
  if (service.name === "db") {
92
93
  dbHandler.registerEventQueueDbHandler(service);
94
+ config.cleanupLocksAndEventsForDev && registerCleanupForDevDb().catch(() => {});
93
95
  }
94
96
  });
95
97
  }
@@ -108,20 +110,28 @@ const initialize = async ({
108
110
  };
109
111
 
110
112
  const readConfigFromFile = async (configFilepath) => {
111
- const fileData = await readFileAsync(configFilepath);
112
- if (/\.ya?ml$/i.test(configFilepath)) {
113
- return yaml.parse(fileData.toString());
114
- }
115
- if (/\.json$/i.test(configFilepath)) {
116
- return JSON.parse(fileData.toString());
113
+ try {
114
+ const fileData = await readFileAsync(configFilepath);
115
+ if (/\.ya?ml$/i.test(configFilepath)) {
116
+ return yaml.parse(fileData.toString());
117
+ }
118
+ if (/\.json$/i.test(configFilepath)) {
119
+ return JSON.parse(fileData.toString());
120
+ }
121
+
122
+ throw new VError(
123
+ {
124
+ name: VERROR_CLUSTER_NAME,
125
+ info: { configFilepath },
126
+ },
127
+ "configFilepath with unsupported extension, allowed extensions are .yaml and .json"
128
+ );
129
+ } catch (err) {
130
+ if (config.useAsCAPOutbox) {
131
+ return {};
132
+ }
133
+ throw err;
117
134
  }
118
- throw new VError(
119
- {
120
- name: VERROR_CLUSTER_NAME,
121
- info: { configFilepath },
122
- },
123
- "configFilepath with unsupported extension, allowed extensions are .yaml and .json"
124
- );
125
135
  };
126
136
 
127
137
  const registerEventProcessors = () => {
@@ -149,9 +159,11 @@ const monkeyPatchCAPOutbox = () => {
149
159
  if (config.useAsCAPOutbox) {
150
160
  Object.defineProperty(cds, "outboxed", {
151
161
  get: () => eventQueueAsOutbox.outboxed,
162
+ configurable: true,
152
163
  });
153
164
  Object.defineProperty(cds, "unboxed", {
154
165
  get: () => eventQueueAsOutbox.unboxed,
166
+ configurable: true,
155
167
  });
156
168
  }
157
169
  };
@@ -213,6 +225,25 @@ const registerCdsShutdown = () => {
213
225
  });
214
226
  };
215
227
 
228
+ const registerCleanupForDevDb = async () => {
229
+ const profile = cds.env.profiles.find((profile) => profile === "development");
230
+ if (!profile) {
231
+ return;
232
+ }
233
+
234
+ const tenantIds = await getAllTenantIds();
235
+ for (const tenantId of tenantIds) {
236
+ await cds.tx({ tenant: tenantId }, async (tx) => {
237
+ await tx.run(DELETE.from(config.tableNameEventLock));
238
+ await tx.run(
239
+ UPDATE.entity(config.tableNameEventQueue).where({ status: EventProcessingStatus.InProgress }).set({
240
+ status: EventProcessingStatus.Error,
241
+ })
242
+ );
243
+ });
244
+ }
245
+ };
246
+
216
247
  module.exports = {
217
248
  initialize,
218
249
  };