@cap-js-community/event-queue 0.2.1 → 0.2.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 +1 -1
- package/src/EventQueueError.js +60 -0
- package/src/EventQueueProcessorBase.js +119 -17
- package/src/config.js +79 -13
- package/src/dbHandler.js +5 -3
- package/src/index.js +1 -1
- package/src/initialize.js +31 -34
- package/src/periodicEvents.js +107 -0
- package/src/processEventQueue.js +74 -2
- package/src/publishEvent.js +12 -5
- package/src/redisPubSub.js +3 -4
- package/src/runner.js +99 -33
- package/src/shared/WorkerQueue.js +2 -3
- package/src/shared/cdsHelper.js +2 -2
- package/src/shared/common.js +15 -1
- package/src/shared/distributedLock.js +12 -20
- package/src/shared/{EventScheduler.js → eventScheduler.js} +21 -8
|
@@ -3,15 +3,10 @@
|
|
|
3
3
|
const redis = require("./redis");
|
|
4
4
|
const config = require("../config");
|
|
5
5
|
const cdsHelper = require("./cdsHelper");
|
|
6
|
-
const { getConfigInstance } = require("../config");
|
|
7
6
|
|
|
8
|
-
const acquireLock = async (
|
|
9
|
-
context,
|
|
10
|
-
key,
|
|
11
|
-
{ tenantScoped = true, expiryTime = config.getConfigInstance().globalTxTimeout } = {}
|
|
12
|
-
) => {
|
|
7
|
+
const acquireLock = async (context, key, { tenantScoped = true, expiryTime = config.globalTxTimeout } = {}) => {
|
|
13
8
|
const fullKey = _generateKey(context, tenantScoped, key);
|
|
14
|
-
if (config.
|
|
9
|
+
if (config.redisEnabled) {
|
|
15
10
|
return await _acquireLockRedis(context, fullKey, expiryTime);
|
|
16
11
|
} else {
|
|
17
12
|
return await _acquireLockDB(context, fullKey, expiryTime);
|
|
@@ -22,10 +17,10 @@ const setValueWithExpire = async (
|
|
|
22
17
|
context,
|
|
23
18
|
key,
|
|
24
19
|
value,
|
|
25
|
-
{ tenantScoped = true, expiryTime = config.
|
|
20
|
+
{ tenantScoped = true, expiryTime = config.globalTxTimeout, overrideValue = false } = {}
|
|
26
21
|
) => {
|
|
27
22
|
const fullKey = _generateKey(context, tenantScoped, key);
|
|
28
|
-
if (config.
|
|
23
|
+
if (config.redisEnabled) {
|
|
29
24
|
return await _acquireLockRedis(context, fullKey, expiryTime, {
|
|
30
25
|
value,
|
|
31
26
|
overrideValue,
|
|
@@ -40,7 +35,7 @@ const setValueWithExpire = async (
|
|
|
40
35
|
|
|
41
36
|
const releaseLock = async (context, key, { tenantScoped = true } = {}) => {
|
|
42
37
|
const fullKey = _generateKey(context, tenantScoped, key);
|
|
43
|
-
if (config.
|
|
38
|
+
if (config.redisEnabled) {
|
|
44
39
|
return await _releaseLockRedis(context, fullKey);
|
|
45
40
|
} else {
|
|
46
41
|
return await _releaseLockDb(context, fullKey);
|
|
@@ -49,7 +44,7 @@ const releaseLock = async (context, key, { tenantScoped = true } = {}) => {
|
|
|
49
44
|
|
|
50
45
|
const checkLockExistsAndReturnValue = async (context, key, { tenantScoped = true } = {}) => {
|
|
51
46
|
const fullKey = _generateKey(context, tenantScoped, key);
|
|
52
|
-
if (config.
|
|
47
|
+
if (config.redisEnabled) {
|
|
53
48
|
return await _checkLockExistsRedis(context, fullKey);
|
|
54
49
|
} else {
|
|
55
50
|
return await _checkLockExistsDb(context, fullKey);
|
|
@@ -72,9 +67,8 @@ const _checkLockExistsRedis = async (context, fullKey) => {
|
|
|
72
67
|
|
|
73
68
|
const _checkLockExistsDb = async (context, fullKey) => {
|
|
74
69
|
let result;
|
|
75
|
-
const configInstance = getConfigInstance();
|
|
76
70
|
await cdsHelper.executeInNewTransaction(context, "distributedLock-checkExists", async (tx) => {
|
|
77
|
-
result = await tx.run(SELECT.one.from(
|
|
71
|
+
result = await tx.run(SELECT.one.from(config.tableNameEventLock).where("code =", fullKey));
|
|
78
72
|
});
|
|
79
73
|
return result?.value;
|
|
80
74
|
};
|
|
@@ -85,19 +79,17 @@ const _releaseLockRedis = async (context, fullKey) => {
|
|
|
85
79
|
};
|
|
86
80
|
|
|
87
81
|
const _releaseLockDb = async (context, fullKey) => {
|
|
88
|
-
const configInstance = getConfigInstance();
|
|
89
82
|
await cdsHelper.executeInNewTransaction(context, "distributedLock-release", async (tx) => {
|
|
90
|
-
await tx.run(DELETE.from(
|
|
83
|
+
await tx.run(DELETE.from(config.tableNameEventLock).where("code =", fullKey));
|
|
91
84
|
});
|
|
92
85
|
};
|
|
93
86
|
|
|
94
87
|
const _acquireLockDB = async (context, fullKey, expiryTime, { value = "true", overrideValue = false } = {}) => {
|
|
95
88
|
let result;
|
|
96
|
-
const configInstance = getConfigInstance();
|
|
97
89
|
await cdsHelper.executeInNewTransaction(context, "distributedLock-acquire", async (tx) => {
|
|
98
90
|
try {
|
|
99
91
|
await tx.run(
|
|
100
|
-
INSERT.into(
|
|
92
|
+
INSERT.into(config.tableNameEventLock).entries({
|
|
101
93
|
code: fullKey,
|
|
102
94
|
value,
|
|
103
95
|
})
|
|
@@ -109,14 +101,14 @@ const _acquireLockDB = async (context, fullKey, expiryTime, { value = "true", ov
|
|
|
109
101
|
if (!overrideValue) {
|
|
110
102
|
currentEntry = await tx.run(
|
|
111
103
|
SELECT.one
|
|
112
|
-
.from(
|
|
113
|
-
.forUpdate({ wait: config.
|
|
104
|
+
.from(config.tableNameEventLock)
|
|
105
|
+
.forUpdate({ wait: config.forUpdateTimeout })
|
|
114
106
|
.where("code =", fullKey)
|
|
115
107
|
);
|
|
116
108
|
}
|
|
117
109
|
if (overrideValue || (currentEntry && new Date(currentEntry.createdAt).getTime() + expiryTime <= Date.now())) {
|
|
118
110
|
await tx.run(
|
|
119
|
-
UPDATE.entity(
|
|
111
|
+
UPDATE.entity(config.tableNameEventLock)
|
|
120
112
|
.set({
|
|
121
113
|
createdAt: new Date().toISOString(),
|
|
122
114
|
value,
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
const cds = require("@sap/cds");
|
|
4
4
|
|
|
5
5
|
const { broadcastEvent } = require("../redisPubSub");
|
|
6
|
+
const config = require("./../config");
|
|
6
7
|
|
|
7
|
-
const COMPONENT_NAME = "eventQueue/shared/
|
|
8
|
+
const COMPONENT_NAME = "eventQueue/shared/eventScheduler";
|
|
8
9
|
|
|
9
10
|
let instance;
|
|
10
11
|
class EventScheduler {
|
|
@@ -12,10 +13,8 @@ class EventScheduler {
|
|
|
12
13
|
constructor() {}
|
|
13
14
|
|
|
14
15
|
scheduleEvent(tenantId, type, subType, startAfter) {
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const roundUpDate = new Date(startAfter.getTime() + secondsUntilNextTen * 1000);
|
|
18
|
-
const key = [tenantId, type, subType, roundUpDate.toISOString()].join("##");
|
|
16
|
+
const { date, relative } = this.calculateOffset(type, subType, startAfter);
|
|
17
|
+
const key = [tenantId, type, subType, date.toISOString()].join("##");
|
|
19
18
|
if (this.#scheduledEvents[key]) {
|
|
20
19
|
return; // event combination already scheduled
|
|
21
20
|
}
|
|
@@ -23,7 +22,7 @@ class EventScheduler {
|
|
|
23
22
|
cds.log(COMPONENT_NAME).info("scheduling event queue run for delayed event", {
|
|
24
23
|
type,
|
|
25
24
|
subType,
|
|
26
|
-
delaySeconds: (
|
|
25
|
+
delaySeconds: (date.getTime() - Date.now()) / 1000,
|
|
27
26
|
});
|
|
28
27
|
setTimeout(() => {
|
|
29
28
|
delete this.#scheduledEvents[key];
|
|
@@ -32,10 +31,24 @@ class EventScheduler {
|
|
|
32
31
|
tenantId,
|
|
33
32
|
type,
|
|
34
33
|
subType,
|
|
35
|
-
scheduledFor:
|
|
34
|
+
scheduledFor: date.toISOString(),
|
|
36
35
|
});
|
|
37
36
|
});
|
|
38
|
-
},
|
|
37
|
+
}, relative).unref();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
calculateOffset(type, subType, startAfter) {
|
|
41
|
+
const eventConfig = config.getEventConfig(type, subType);
|
|
42
|
+
const scheduleWithoutDelay = config.isPeriodicEvent(type, subType) && eventConfig.interval < 30 * 1000;
|
|
43
|
+
const date = scheduleWithoutDelay ? startAfter : this.calculateFutureTime(startAfter, 10);
|
|
44
|
+
|
|
45
|
+
return { date, relative: date.getTime() - Date.now() };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
calculateFutureTime(date, seoncds) {
|
|
49
|
+
const startAfterSeconds = date.getSeconds();
|
|
50
|
+
const secondsUntil = seoncds - (startAfterSeconds % seoncds);
|
|
51
|
+
return new Date(date.getTime() + secondsUntil * 1000);
|
|
39
52
|
}
|
|
40
53
|
|
|
41
54
|
clearScheduledEvents() {
|