@cap-js-community/event-queue 1.11.0-beta.5 → 1.11.0
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 +8 -8
- package/src/redis/redisPub.js +1 -1
- package/src/runner/runner.js +3 -3
- package/src/shared/cdsHelper.js +0 -31
- package/src/shared/common.js +1 -1
- package/src/shared/distributedLock.js +17 -7
- package/srv/service/admin-service.cds +0 -8
- package/srv/service/admin-service.js +1 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cap-js-community/event-queue",
|
|
3
|
-
"version": "1.11.0
|
|
3
|
+
"version": "1.11.0",
|
|
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",
|
|
@@ -47,24 +47,24 @@
|
|
|
47
47
|
"node": ">=18"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@sap/xssec": "^4.
|
|
51
|
-
"cron-parser": "^5.
|
|
50
|
+
"@sap/xssec": "^4.10.0",
|
|
51
|
+
"cron-parser": "^5.4.0",
|
|
52
52
|
"redis": "^4.7.0",
|
|
53
53
|
"verror": "^1.10.1",
|
|
54
54
|
"yaml": "^2.7.1"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@cap-js/cds-test": "^0.4.0",
|
|
58
|
-
"@cap-js/hana": "^2.
|
|
59
|
-
"@cap-js/sqlite": "^2.0.
|
|
60
|
-
"@sap/cds": "^9.
|
|
61
|
-
"@sap/cds-dk": "^9.
|
|
58
|
+
"@cap-js/hana": "^2.3.3",
|
|
59
|
+
"@cap-js/sqlite": "^2.0.3",
|
|
60
|
+
"@sap/cds": "^9.4.1",
|
|
61
|
+
"@sap/cds-dk": "^9.4.1",
|
|
62
62
|
"eslint": "^8.57.0",
|
|
63
63
|
"eslint-config-prettier": "^9.1.0",
|
|
64
64
|
"eslint-plugin-jest": "^28.6.0",
|
|
65
65
|
"eslint-plugin-node": "^11.1.0",
|
|
66
66
|
"express": "^4.21.2",
|
|
67
|
-
"hdb": "^2.
|
|
67
|
+
"hdb": "^2.26.1",
|
|
68
68
|
"jest": "^29.7.0",
|
|
69
69
|
"prettier": "^2.8.8",
|
|
70
70
|
"sqlite3": "^5.1.7",
|
package/src/redis/redisPub.js
CHANGED
|
@@ -77,7 +77,7 @@ const broadcastEvent = async (tenantId, events, forceBroadcast = false) => {
|
|
|
77
77
|
for (let i = 0; i < TRIES_FOR_PUBLISH_PERIODIC_EVENT; i++) {
|
|
78
78
|
const result = eventConfig.multiInstanceProcessing
|
|
79
79
|
? false
|
|
80
|
-
: await distributedLock.
|
|
80
|
+
: await distributedLock.checkLockExists(context, [type, subType].join("##"));
|
|
81
81
|
if (result) {
|
|
82
82
|
logger.debug("skip publish redis event as no lock is available", {
|
|
83
83
|
type,
|
package/src/runner/runner.js
CHANGED
|
@@ -405,7 +405,7 @@ const _acquireRunId = async (context) => {
|
|
|
405
405
|
overrideValue: true,
|
|
406
406
|
});
|
|
407
407
|
} else {
|
|
408
|
-
runId = await distributedLock.
|
|
408
|
+
runId = await distributedLock.getValue(context, EVENT_QUEUE_RUN_ID, {
|
|
409
409
|
tenantScoped: false,
|
|
410
410
|
});
|
|
411
411
|
}
|
|
@@ -422,7 +422,7 @@ const _calculateOffsetForFirstRun = async () => {
|
|
|
422
422
|
try {
|
|
423
423
|
await trace(dummyContext, "calculateOffsetForFirstRun", async () => {
|
|
424
424
|
if (eventQueueConfig.redisEnabled) {
|
|
425
|
-
let lastRunTs = await distributedLock.
|
|
425
|
+
let lastRunTs = await distributedLock.getValue(dummyContext, EVENT_QUEUE_RUN_TS, {
|
|
426
426
|
tenantScoped: false,
|
|
427
427
|
});
|
|
428
428
|
if (!lastRunTs) {
|
|
@@ -434,7 +434,7 @@ const _calculateOffsetForFirstRun = async () => {
|
|
|
434
434
|
if (couldSetValue) {
|
|
435
435
|
lastRunTs = ts;
|
|
436
436
|
} else {
|
|
437
|
-
lastRunTs = await distributedLock.
|
|
437
|
+
lastRunTs = await distributedLock.getValue(dummyContext, EVENT_QUEUE_RUN_TS, {
|
|
438
438
|
tenantScoped: false,
|
|
439
439
|
});
|
|
440
440
|
}
|
package/src/shared/cdsHelper.js
CHANGED
|
@@ -165,38 +165,7 @@ const getAllTenantIds = async () => {
|
|
|
165
165
|
}, []);
|
|
166
166
|
};
|
|
167
167
|
|
|
168
|
-
const TENANT_COLUMNS = ["subscribedSubdomain", "createdAt", "modifiedAt"];
|
|
169
|
-
|
|
170
|
-
const getAllTenantWithMetadata = async () => {
|
|
171
|
-
const response = await _getAllTenantBase();
|
|
172
|
-
if (!response) {
|
|
173
|
-
return null;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
return response.reduce(async (result, row) => {
|
|
177
|
-
const tenantId = row.subscribedTenantId ?? row.tenant;
|
|
178
|
-
result = await result;
|
|
179
|
-
if (await common.isTenantIdValidCb(TenantIdCheckTypes.eventProcessing, tenantId)) {
|
|
180
|
-
const data = Object.entries(row).reduce(
|
|
181
|
-
(result, [key, value]) => {
|
|
182
|
-
if (TENANT_COLUMNS.includes(key)) {
|
|
183
|
-
result[key] = value;
|
|
184
|
-
} else {
|
|
185
|
-
result.metadata[key] = value;
|
|
186
|
-
}
|
|
187
|
-
return result;
|
|
188
|
-
},
|
|
189
|
-
{ metadata: {} }
|
|
190
|
-
);
|
|
191
|
-
data.metadata = JSON.stringify(data.metadata);
|
|
192
|
-
result.push(data);
|
|
193
|
-
}
|
|
194
|
-
return result;
|
|
195
|
-
}, []);
|
|
196
|
-
};
|
|
197
|
-
|
|
198
168
|
module.exports = {
|
|
199
169
|
executeInNewTransaction,
|
|
200
170
|
getAllTenantIds,
|
|
201
|
-
getAllTenantWithMetadata,
|
|
202
171
|
};
|
package/src/shared/common.js
CHANGED
|
@@ -92,7 +92,7 @@ const hashStringTo32Bit = (value) => crypto.createHash("sha256").update(String(v
|
|
|
92
92
|
const _getNewAuthContext = async (tenantId) => {
|
|
93
93
|
try {
|
|
94
94
|
if (!_getNewAuthContext._xsuaaService) {
|
|
95
|
-
_getNewAuthContext._xsuaaService = new xssec.XsuaaService(cds.requires
|
|
95
|
+
_getNewAuthContext._xsuaaService = new xssec.XsuaaService(cds.requires["xsuaa-eventQueue"]?.credentials);
|
|
96
96
|
}
|
|
97
97
|
const authService = _getNewAuthContext._xsuaaService;
|
|
98
98
|
const token = await authService.fetchClientCredentialsToken({ zid: tenantId });
|
|
@@ -60,12 +60,21 @@ const releaseLock = async (context, key, { tenantScoped = true } = {}) => {
|
|
|
60
60
|
}
|
|
61
61
|
};
|
|
62
62
|
|
|
63
|
-
const
|
|
63
|
+
const checkLockExists = async (context, key, { tenantScoped = true } = {}) => {
|
|
64
64
|
const fullKey = _generateKey(context, tenantScoped, key);
|
|
65
65
|
if (config.redisEnabled) {
|
|
66
|
-
return await
|
|
66
|
+
return !!(await _getLockValueRedis(context, fullKey));
|
|
67
67
|
} else {
|
|
68
|
-
return await
|
|
68
|
+
return !!(await _getLockValueDb(context, fullKey));
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const getValue = async (context, key, { tenantScoped = true } = {}) => {
|
|
73
|
+
const fullKey = _generateKey(context, tenantScoped, key);
|
|
74
|
+
if (config.redisEnabled) {
|
|
75
|
+
return await _getLockValueRedis(context, fullKey);
|
|
76
|
+
} else {
|
|
77
|
+
return await _getLockValueDb(context, fullKey);
|
|
69
78
|
}
|
|
70
79
|
};
|
|
71
80
|
|
|
@@ -106,12 +115,12 @@ const _renewLockRedis = async (context, fullKey, expiryTime, { value = "true" }
|
|
|
106
115
|
return result === REDIS_COMMAND_OK;
|
|
107
116
|
};
|
|
108
117
|
|
|
109
|
-
const
|
|
118
|
+
const _getLockValueRedis = async (context, fullKey) => {
|
|
110
119
|
const client = await redis.createMainClientAndConnect(config.redisOptions);
|
|
111
|
-
return await client.
|
|
120
|
+
return await client.get(fullKey);
|
|
112
121
|
};
|
|
113
122
|
|
|
114
|
-
const
|
|
123
|
+
const _getLockValueDb = async (context, fullKey) => {
|
|
115
124
|
let result;
|
|
116
125
|
await cdsHelper.executeInNewTransaction(context, "distributedLock-checkExists", async (tx) => {
|
|
117
126
|
result = await tx.run(SELECT.one.from(config.tableNameEventLock).where("code =", fullKey));
|
|
@@ -259,7 +268,8 @@ const shutdownHandler = async () => {
|
|
|
259
268
|
module.exports = {
|
|
260
269
|
acquireLock,
|
|
261
270
|
releaseLock,
|
|
262
|
-
|
|
271
|
+
checkLockExists,
|
|
272
|
+
getValue,
|
|
263
273
|
setValueWithExpire,
|
|
264
274
|
shutdownHandler,
|
|
265
275
|
renewLock,
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
const cds = require("@sap/cds");
|
|
4
|
-
const cdsHelper = require("../../src/shared/cdsHelper");
|
|
5
4
|
const { EventProcessingStatus } = require("../../src");
|
|
6
5
|
const config = require("../../src/config");
|
|
7
6
|
const distributedLock = require("../../src/shared/distributedLock");
|
|
@@ -9,7 +8,7 @@ const redisPub = require("../../src/redis/redisPub");
|
|
|
9
8
|
|
|
10
9
|
module.exports = class AdminService extends cds.ApplicationService {
|
|
11
10
|
async init() {
|
|
12
|
-
const { Event: EventService,
|
|
11
|
+
const { Event: EventService, Lock: LockService } = this.entities();
|
|
13
12
|
const { Event: EventDb } = cds.db.entities("sap.eventqueue");
|
|
14
13
|
const { landscape, space } = this.getLandscapeAndSpace();
|
|
15
14
|
|
|
@@ -18,9 +17,6 @@ module.exports = class AdminService extends cds.ApplicationService {
|
|
|
18
17
|
req.reject(403, "Admin service is disabled by configuration");
|
|
19
18
|
}
|
|
20
19
|
|
|
21
|
-
if (req.target.name === Tenant.name) {
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
20
|
const headers = Object.assign({}, req.headers, req.req?.headers);
|
|
25
21
|
const tenant = headers["z-id"] ?? req.data.tenant;
|
|
26
22
|
|
|
@@ -61,11 +57,6 @@ module.exports = class AdminService extends cds.ApplicationService {
|
|
|
61
57
|
}));
|
|
62
58
|
});
|
|
63
59
|
|
|
64
|
-
this.on("READ", Tenant, async () => {
|
|
65
|
-
const tenants = await cdsHelper.getAllTenantWithMetadata();
|
|
66
|
-
return tenants ?? [];
|
|
67
|
-
});
|
|
68
|
-
|
|
69
60
|
this.on("setStatusAndAttempts", async (req) => {
|
|
70
61
|
const tenant = req.headers["z-id"];
|
|
71
62
|
cds.log("eventQueue").info("Restarting processing for event queue");
|