@cap-js-community/event-queue 0.1.49 → 0.1.51
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 +2 -2
- package/cds-plugin.js +1 -1
- package/package.json +9 -2
- package/src/EventQueueError.js +5 -10
- package/src/EventQueueProcessorBase.js +315 -343
- package/src/config.js +1 -4
- package/src/constants.js +5 -0
- package/src/dbHandler.js +1 -4
- package/src/initialize.js +11 -39
- package/src/processEventQueue.js +65 -154
- package/src/publishEvent.js +1 -3
- package/src/redisPubSub.js +6 -20
- package/src/runner.js +40 -78
- package/src/shared/PerformanceTracer.js +1 -3
- package/src/shared/SetIntervalDriftSafe.js +37 -0
- package/src/shared/WorkerQueue.js +3 -14
- package/src/shared/cdsHelper.js +2 -11
- package/src/shared/common.js +2 -7
- package/src/shared/distributedLock.js +41 -85
- package/src/shared/redis.js +1 -3
package/src/runner.js
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
const uuid = require("uuid");
|
|
4
4
|
|
|
5
5
|
const eventQueueConfig = require("./config");
|
|
6
|
-
const cdsHelper = require("./shared/cdsHelper");
|
|
7
6
|
const { eventQueueRunner } = require("./processEventQueue");
|
|
8
|
-
const distributedLock = require("./shared/distributedLock");
|
|
9
7
|
const { getWorkerPoolInstance } = require("./shared/WorkerQueue");
|
|
10
|
-
const
|
|
8
|
+
const cdsHelper = require("./shared/cdsHelper");
|
|
9
|
+
const distributedLock = require("./shared/distributedLock");
|
|
10
|
+
const SetIntervalDriftSafe = require("./shared/SetIntervalDriftSafe");
|
|
11
11
|
|
|
12
12
|
const COMPONENT_NAME = "eventQueue/runner";
|
|
13
13
|
const EVENT_QUEUE_RUN_ID = "EVENT_QUEUE_RUN_ID";
|
|
@@ -26,17 +26,13 @@ const _scheduleFunction = async (fn) => {
|
|
|
26
26
|
const configInstance = eventQueueConfig.getConfigInstance();
|
|
27
27
|
const eventsForAutomaticRun = configInstance.events;
|
|
28
28
|
if (!eventsForAutomaticRun.length) {
|
|
29
|
-
LOGGER.warn(
|
|
30
|
-
"no events for automatic run are configured - skipping runner registration"
|
|
31
|
-
);
|
|
29
|
+
LOGGER.warn("no events for automatic run are configured - skipping runner registration");
|
|
32
30
|
return;
|
|
33
31
|
}
|
|
34
32
|
|
|
35
33
|
const fnWithRunningCheck = () => {
|
|
36
34
|
if (configInstance.isRunnerDeactivated) {
|
|
37
|
-
LOGGER.info(
|
|
38
|
-
"runner is deactivated via config variable. Skipping this run."
|
|
39
|
-
);
|
|
35
|
+
LOGGER.info("runner is deactivated via config variable. Skipping this run.");
|
|
40
36
|
return;
|
|
41
37
|
}
|
|
42
38
|
return fn();
|
|
@@ -45,14 +41,13 @@ const _scheduleFunction = async (fn) => {
|
|
|
45
41
|
const offsetDependingOnLastRun = await _calculateOffsetForFirstRun();
|
|
46
42
|
|
|
47
43
|
LOGGER.info("first event-queue run scheduled", {
|
|
48
|
-
firstRunScheduledFor: new Date(
|
|
49
|
-
Date.now() + offsetDependingOnLastRun
|
|
50
|
-
).toISOString(),
|
|
44
|
+
firstRunScheduledFor: new Date(Date.now() + offsetDependingOnLastRun).toISOString(),
|
|
51
45
|
});
|
|
52
46
|
|
|
53
47
|
setTimeout(() => {
|
|
54
48
|
fnWithRunningCheck();
|
|
55
|
-
|
|
49
|
+
const intervalRunner = new SetIntervalDriftSafe(configInstance.runInterval);
|
|
50
|
+
intervalRunner.run(fnWithRunningCheck);
|
|
56
51
|
}, offsetDependingOnLastRun).unref();
|
|
57
52
|
};
|
|
58
53
|
|
|
@@ -72,9 +67,7 @@ const _multiTenancyRedis = async () => {
|
|
|
72
67
|
|
|
73
68
|
const _multiTenancyDb = async () => {
|
|
74
69
|
try {
|
|
75
|
-
LOGGER.info(
|
|
76
|
-
"executing event queue run for single instance and multi tenant"
|
|
77
|
-
);
|
|
70
|
+
LOGGER.info("executing event queue run for single instance and multi tenant");
|
|
78
71
|
const tenantIds = await cdsHelper.getAllTenantIds();
|
|
79
72
|
_executeAllTenants(tenantIds, EVENT_QUEUE_RUN_ID);
|
|
80
73
|
} catch (err) {
|
|
@@ -91,13 +84,9 @@ const _executeAllTenants = (tenantIds, runId) => {
|
|
|
91
84
|
workerQueueInstance.addToQueue(async () => {
|
|
92
85
|
try {
|
|
93
86
|
const tenantContext = new cds.EventContext({ tenant: tenantId });
|
|
94
|
-
const couldAcquireLock = await distributedLock.acquireLock(
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
{
|
|
98
|
-
expiryTime: configInstance.runInterval * 0.95,
|
|
99
|
-
}
|
|
100
|
-
);
|
|
87
|
+
const couldAcquireLock = await distributedLock.acquireLock(tenantContext, runId, {
|
|
88
|
+
expiryTime: configInstance.runInterval * 0.95,
|
|
89
|
+
});
|
|
101
90
|
if (!couldAcquireLock) {
|
|
102
91
|
return;
|
|
103
92
|
}
|
|
@@ -129,55 +118,38 @@ const _executeRunForTenant = async (tenantId, runId) => {
|
|
|
129
118
|
});
|
|
130
119
|
await eventQueueRunner(context, eventsForAutomaticRun);
|
|
131
120
|
} catch (err) {
|
|
132
|
-
LOGGER.error(
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
redisEnabled: configInstance.redisEnabled,
|
|
137
|
-
}
|
|
138
|
-
);
|
|
121
|
+
LOGGER.error(`Couldn't process eventQueue for tenant! Next try after defined interval. Error: ${err}`, {
|
|
122
|
+
tenantId,
|
|
123
|
+
redisEnabled: configInstance.redisEnabled,
|
|
124
|
+
});
|
|
139
125
|
}
|
|
140
126
|
};
|
|
141
127
|
|
|
142
128
|
const _acquireRunId = async (context) => {
|
|
143
129
|
const configInstance = eventQueueConfig.getConfigInstance();
|
|
144
130
|
let runId = uuid.v4();
|
|
145
|
-
const couldSetValue = await distributedLock.setValueWithExpire(
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
{
|
|
150
|
-
tenantScoped: false,
|
|
151
|
-
expiryTime: configInstance.runInterval * 0.95,
|
|
152
|
-
}
|
|
153
|
-
);
|
|
131
|
+
const couldSetValue = await distributedLock.setValueWithExpire(context, EVENT_QUEUE_RUN_ID, runId, {
|
|
132
|
+
tenantScoped: false,
|
|
133
|
+
expiryTime: configInstance.runInterval * 0.95,
|
|
134
|
+
});
|
|
154
135
|
|
|
155
136
|
if (couldSetValue) {
|
|
156
|
-
await distributedLock.setValueWithExpire(
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
tenantScoped: false,
|
|
162
|
-
expiryTime: configInstance.runInterval,
|
|
163
|
-
overrideValue: true,
|
|
164
|
-
}
|
|
165
|
-
);
|
|
137
|
+
await distributedLock.setValueWithExpire(context, EVENT_QUEUE_RUN_TS, new Date().toISOString(), {
|
|
138
|
+
tenantScoped: false,
|
|
139
|
+
expiryTime: configInstance.runInterval,
|
|
140
|
+
overrideValue: true,
|
|
141
|
+
});
|
|
166
142
|
} else {
|
|
167
|
-
runId = await distributedLock.checkLockExistsAndReturnValue(
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
{
|
|
171
|
-
tenantScoped: false,
|
|
172
|
-
}
|
|
173
|
-
);
|
|
143
|
+
runId = await distributedLock.checkLockExistsAndReturnValue(context, EVENT_QUEUE_RUN_ID, {
|
|
144
|
+
tenantScoped: false,
|
|
145
|
+
});
|
|
174
146
|
}
|
|
175
147
|
|
|
176
148
|
return runId;
|
|
177
149
|
};
|
|
178
150
|
|
|
179
151
|
const _calculateOffsetForFirstRun = async () => {
|
|
180
|
-
const configInstance = getConfigInstance();
|
|
152
|
+
const configInstance = eventQueueConfig.getConfigInstance();
|
|
181
153
|
let offsetDependingOnLastRun = OFFSET_FIRST_RUN;
|
|
182
154
|
const now = Date.now();
|
|
183
155
|
// NOTE: this is only supported with Redis, because this is a tenant agnostic information
|
|
@@ -185,34 +157,24 @@ const _calculateOffsetForFirstRun = async () => {
|
|
|
185
157
|
try {
|
|
186
158
|
if (configInstance.redisEnabled) {
|
|
187
159
|
const dummyContext = new cds.EventContext({});
|
|
188
|
-
let lastRunTs = await distributedLock.checkLockExistsAndReturnValue(
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
{ tenantScoped: false }
|
|
192
|
-
);
|
|
160
|
+
let lastRunTs = await distributedLock.checkLockExistsAndReturnValue(dummyContext, EVENT_QUEUE_RUN_TS, {
|
|
161
|
+
tenantScoped: false,
|
|
162
|
+
});
|
|
193
163
|
if (!lastRunTs) {
|
|
194
164
|
const ts = new Date(now).toISOString();
|
|
195
|
-
const couldSetValue = await distributedLock.setValueWithExpire(
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
{
|
|
200
|
-
tenantScoped: false,
|
|
201
|
-
expiryTime: configInstance.runInterval,
|
|
202
|
-
}
|
|
203
|
-
);
|
|
165
|
+
const couldSetValue = await distributedLock.setValueWithExpire(dummyContext, EVENT_QUEUE_RUN_TS, ts, {
|
|
166
|
+
tenantScoped: false,
|
|
167
|
+
expiryTime: configInstance.runInterval,
|
|
168
|
+
});
|
|
204
169
|
if (couldSetValue) {
|
|
205
170
|
lastRunTs = ts;
|
|
206
171
|
} else {
|
|
207
|
-
lastRunTs = await distributedLock.checkLockExistsAndReturnValue(
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
{ tenantScoped: false }
|
|
211
|
-
);
|
|
172
|
+
lastRunTs = await distributedLock.checkLockExistsAndReturnValue(dummyContext, EVENT_QUEUE_RUN_TS, {
|
|
173
|
+
tenantScoped: false,
|
|
174
|
+
});
|
|
212
175
|
}
|
|
213
176
|
}
|
|
214
|
-
offsetDependingOnLastRun =
|
|
215
|
-
new Date(lastRunTs).getTime() + configInstance.runInterval - now;
|
|
177
|
+
offsetDependingOnLastRun = new Date(lastRunTs).getTime() + configInstance.runInterval - now;
|
|
216
178
|
}
|
|
217
179
|
} catch (err) {
|
|
218
180
|
LOGGER.error(
|
|
@@ -36,9 +36,7 @@ class PerformanceTracer {
|
|
|
36
36
|
//determine, if an options object was provided as first argument
|
|
37
37
|
if (
|
|
38
38
|
typeof args?.[0] === "object" &&
|
|
39
|
-
(args[0].quantity >= 0 ||
|
|
40
|
-
args[0].threshold > 0 ||
|
|
41
|
-
args[0].additionalQuantityThreshold > 0)
|
|
39
|
+
(args[0].quantity >= 0 || args[0].threshold > 0 || args[0].additionalQuantityThreshold > 0)
|
|
42
40
|
) {
|
|
43
41
|
options = args.shift();
|
|
44
42
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const COMPONENT = "eventQueue/SetIntervalDriftSafe";
|
|
4
|
+
|
|
5
|
+
class SetIntervalDriftSafe {
|
|
6
|
+
#adjustedInterval;
|
|
7
|
+
#interval;
|
|
8
|
+
#expectedCycleTime = 0;
|
|
9
|
+
#nextTickScheduledFor;
|
|
10
|
+
#logger;
|
|
11
|
+
|
|
12
|
+
constructor(interval) {
|
|
13
|
+
this.#interval = interval;
|
|
14
|
+
this.#adjustedInterval = interval;
|
|
15
|
+
this.#logger = cds.log(COMPONENT);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
run(fn) {
|
|
19
|
+
const now = Date.now();
|
|
20
|
+
if (this.#expectedCycleTime === 0) {
|
|
21
|
+
this.#expectedCycleTime = now + this.#interval;
|
|
22
|
+
} else if (now + this.#interval - this.#nextTickScheduledFor < this.#interval) {
|
|
23
|
+
this.#logger.info("overlapping ticks, skipping this run");
|
|
24
|
+
return;
|
|
25
|
+
} else {
|
|
26
|
+
this.#adjustedInterval = this.#interval - (now - this.#expectedCycleTime);
|
|
27
|
+
this.#expectedCycleTime += this.#interval;
|
|
28
|
+
}
|
|
29
|
+
this.#nextTickScheduledFor = now + this.#adjustedInterval;
|
|
30
|
+
setTimeout(() => {
|
|
31
|
+
this.run(fn);
|
|
32
|
+
fn();
|
|
33
|
+
}, this.#adjustedInterval);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
module.exports = SetIntervalDriftSafe;
|
|
@@ -32,31 +32,20 @@ class WorkerQueue {
|
|
|
32
32
|
this.__runningPromises.push(promise);
|
|
33
33
|
promise
|
|
34
34
|
.finally(() => {
|
|
35
|
-
this.__runningPromises.splice(
|
|
36
|
-
this.__runningPromises.indexOf(promise),
|
|
37
|
-
1
|
|
38
|
-
);
|
|
35
|
+
this.__runningPromises.splice(this.__runningPromises.indexOf(promise), 1);
|
|
39
36
|
this._checkForNext();
|
|
40
37
|
})
|
|
41
38
|
.then((...results) => {
|
|
42
39
|
resolve(...results);
|
|
43
40
|
})
|
|
44
41
|
.catch((err) => {
|
|
45
|
-
cds
|
|
46
|
-
.log(COMPONENT_NAME)
|
|
47
|
-
.error(
|
|
48
|
-
"Error happened in WorkQueue. Errors should be caught before! Error:",
|
|
49
|
-
err
|
|
50
|
-
);
|
|
42
|
+
cds.log(COMPONENT_NAME).error("Error happened in WorkQueue. Errors should be caught before! Error:", err);
|
|
51
43
|
reject(err);
|
|
52
44
|
});
|
|
53
45
|
}
|
|
54
46
|
|
|
55
47
|
_checkForNext() {
|
|
56
|
-
if (
|
|
57
|
-
!this.__queue.length ||
|
|
58
|
-
this.__runningPromises.length >= this.__concurrencyLimit
|
|
59
|
-
) {
|
|
48
|
+
if (!this.__queue.length || this.__runningPromises.length >= this.__concurrencyLimit) {
|
|
60
49
|
return;
|
|
61
50
|
}
|
|
62
51
|
const [cb, resolve, reject] = this.__queue.shift();
|
package/src/shared/cdsHelper.js
CHANGED
|
@@ -20,13 +20,7 @@ const COMPONENT_NAME = "eventQueue/cdsHelper";
|
|
|
20
20
|
* @param info {object} Additional information object attached to logging
|
|
21
21
|
* @returns {Promise<boolean>} Promise resolving to true if everything worked fine / false if an error occurred
|
|
22
22
|
*/
|
|
23
|
-
async function executeInNewTransaction(
|
|
24
|
-
context = {},
|
|
25
|
-
transactionTag,
|
|
26
|
-
fn,
|
|
27
|
-
args,
|
|
28
|
-
{ info = {} } = {}
|
|
29
|
-
) {
|
|
23
|
+
async function executeInNewTransaction(context = {}, transactionTag, fn, args, { info = {} } = {}) {
|
|
30
24
|
const parameters = Array.isArray(args) ? args : [args];
|
|
31
25
|
const logger = cds.log(COMPONENT_NAME);
|
|
32
26
|
try {
|
|
@@ -48,10 +42,7 @@ async function executeInNewTransaction(
|
|
|
48
42
|
} else {
|
|
49
43
|
const contextTx = cds.tx(context);
|
|
50
44
|
const contextTxState = contextTx.ready;
|
|
51
|
-
if (
|
|
52
|
-
!contextTxState ||
|
|
53
|
-
["committed", "rolled back"].includes(contextTxState)
|
|
54
|
-
) {
|
|
45
|
+
if (!contextTxState || ["committed", "rolled back"].includes(contextTxState)) {
|
|
55
46
|
await cds.tx(
|
|
56
47
|
{
|
|
57
48
|
id: context.id,
|
package/src/shared/common.js
CHANGED
|
@@ -56,10 +56,7 @@ class Funnel {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
// map function call to promise
|
|
59
|
-
const p =
|
|
60
|
-
f.constructor.name === "AsyncFunction"
|
|
61
|
-
? f(...args)
|
|
62
|
-
: Promise.resolve().then(() => f(...args));
|
|
59
|
+
const p = f.constructor.name === "AsyncFunction" ? f(...args) : Promise.resolve().then(() => f(...args));
|
|
63
60
|
|
|
64
61
|
// create promise for book keeping
|
|
65
62
|
const workload = p.finally(() => {
|
|
@@ -100,9 +97,7 @@ const limiter = async (limit, payloads, iterator) => {
|
|
|
100
97
|
returnPromises.push(p);
|
|
101
98
|
|
|
102
99
|
if (limit <= payloads.length) {
|
|
103
|
-
const e = p
|
|
104
|
-
.catch(() => {})
|
|
105
|
-
.finally(() => runningPromises.splice(runningPromises.indexOf(e), 1));
|
|
100
|
+
const e = p.catch(() => {}).finally(() => runningPromises.splice(runningPromises.indexOf(e), 1));
|
|
106
101
|
runningPromises.push(e);
|
|
107
102
|
if (limit <= runningPromises.length) {
|
|
108
103
|
await Promise.race(runningPromises);
|
|
@@ -8,10 +8,7 @@ const { getConfigInstance } = require("../config");
|
|
|
8
8
|
const acquireLock = async (
|
|
9
9
|
context,
|
|
10
10
|
key,
|
|
11
|
-
{
|
|
12
|
-
tenantScoped = true,
|
|
13
|
-
expiryTime = config.getConfigInstance().globalTxTimeout,
|
|
14
|
-
} = {}
|
|
11
|
+
{ tenantScoped = true, expiryTime = config.getConfigInstance().globalTxTimeout } = {}
|
|
15
12
|
) => {
|
|
16
13
|
const fullKey = _generateKey(context, tenantScoped, key);
|
|
17
14
|
if (config.getConfigInstance().redisEnabled) {
|
|
@@ -25,11 +22,7 @@ const setValueWithExpire = async (
|
|
|
25
22
|
context,
|
|
26
23
|
key,
|
|
27
24
|
value,
|
|
28
|
-
{
|
|
29
|
-
tenantScoped = true,
|
|
30
|
-
expiryTime = config.getConfigInstance().globalTxTimeout,
|
|
31
|
-
overrideValue = false,
|
|
32
|
-
} = {}
|
|
25
|
+
{ tenantScoped = true, expiryTime = config.getConfigInstance().globalTxTimeout, overrideValue = false } = {}
|
|
33
26
|
) => {
|
|
34
27
|
const fullKey = _generateKey(context, tenantScoped, key);
|
|
35
28
|
if (config.getConfigInstance().redisEnabled) {
|
|
@@ -54,11 +47,7 @@ const releaseLock = async (context, key, { tenantScoped = true } = {}) => {
|
|
|
54
47
|
}
|
|
55
48
|
};
|
|
56
49
|
|
|
57
|
-
const checkLockExistsAndReturnValue = async (
|
|
58
|
-
context,
|
|
59
|
-
key,
|
|
60
|
-
{ tenantScoped = true } = {}
|
|
61
|
-
) => {
|
|
50
|
+
const checkLockExistsAndReturnValue = async (context, key, { tenantScoped = true } = {}) => {
|
|
62
51
|
const fullKey = _generateKey(context, tenantScoped, key);
|
|
63
52
|
if (config.getConfigInstance().redisEnabled) {
|
|
64
53
|
return await _checkLockExistsRedis(context, fullKey);
|
|
@@ -67,12 +56,7 @@ const checkLockExistsAndReturnValue = async (
|
|
|
67
56
|
}
|
|
68
57
|
};
|
|
69
58
|
|
|
70
|
-
const _acquireLockRedis = async (
|
|
71
|
-
context,
|
|
72
|
-
fullKey,
|
|
73
|
-
expiryTime,
|
|
74
|
-
{ value = "true", overrideValue = false } = {}
|
|
75
|
-
) => {
|
|
59
|
+
const _acquireLockRedis = async (context, fullKey, expiryTime, { value = "true", overrideValue = false } = {}) => {
|
|
76
60
|
const client = await redis.createMainClientAndConnect();
|
|
77
61
|
const result = await client.set(fullKey, value, {
|
|
78
62
|
PX: expiryTime,
|
|
@@ -89,17 +73,9 @@ const _checkLockExistsRedis = async (context, fullKey) => {
|
|
|
89
73
|
const _checkLockExistsDb = async (context, fullKey) => {
|
|
90
74
|
let result;
|
|
91
75
|
const configInstance = getConfigInstance();
|
|
92
|
-
await cdsHelper.executeInNewTransaction(
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
async (tx) => {
|
|
96
|
-
result = await tx.run(
|
|
97
|
-
SELECT.one
|
|
98
|
-
.from(configInstance.tableNameEventLock)
|
|
99
|
-
.where("code =", fullKey)
|
|
100
|
-
);
|
|
101
|
-
}
|
|
102
|
-
);
|
|
76
|
+
await cdsHelper.executeInNewTransaction(context, "distributedLock-checkExists", async (tx) => {
|
|
77
|
+
result = await tx.run(SELECT.one.from(configInstance.tableNameEventLock).where("code =", fullKey));
|
|
78
|
+
});
|
|
103
79
|
return result?.value;
|
|
104
80
|
};
|
|
105
81
|
|
|
@@ -110,69 +86,49 @@ const _releaseLockRedis = async (context, fullKey) => {
|
|
|
110
86
|
|
|
111
87
|
const _releaseLockDb = async (context, fullKey) => {
|
|
112
88
|
const configInstance = getConfigInstance();
|
|
113
|
-
await cdsHelper.executeInNewTransaction(
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
async (tx) => {
|
|
117
|
-
await tx.run(
|
|
118
|
-
DELETE.from(configInstance.tableNameEventLock).where("code =", fullKey)
|
|
119
|
-
);
|
|
120
|
-
}
|
|
121
|
-
);
|
|
89
|
+
await cdsHelper.executeInNewTransaction(context, "distributedLock-release", async (tx) => {
|
|
90
|
+
await tx.run(DELETE.from(configInstance.tableNameEventLock).where("code =", fullKey));
|
|
91
|
+
});
|
|
122
92
|
};
|
|
123
93
|
|
|
124
|
-
const _acquireLockDB = async (
|
|
125
|
-
context,
|
|
126
|
-
fullKey,
|
|
127
|
-
expiryTime,
|
|
128
|
-
{ value = "true", overrideValue = false } = {}
|
|
129
|
-
) => {
|
|
94
|
+
const _acquireLockDB = async (context, fullKey, expiryTime, { value = "true", overrideValue = false } = {}) => {
|
|
130
95
|
let result;
|
|
131
96
|
const configInstance = getConfigInstance();
|
|
132
|
-
await cdsHelper.executeInNewTransaction(
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
97
|
+
await cdsHelper.executeInNewTransaction(context, "distributedLock-acquire", async (tx) => {
|
|
98
|
+
try {
|
|
99
|
+
await tx.run(
|
|
100
|
+
INSERT.into(configInstance.tableNameEventLock).entries({
|
|
101
|
+
code: fullKey,
|
|
102
|
+
value,
|
|
103
|
+
})
|
|
104
|
+
);
|
|
105
|
+
result = true;
|
|
106
|
+
} catch (err) {
|
|
107
|
+
let currentEntry;
|
|
108
|
+
|
|
109
|
+
if (!overrideValue) {
|
|
110
|
+
currentEntry = await tx.run(
|
|
111
|
+
SELECT.one
|
|
112
|
+
.from(configInstance.tableNameEventLock)
|
|
113
|
+
.forUpdate({ wait: config.getConfigInstance().forUpdateTimeout })
|
|
114
|
+
.where("code =", fullKey)
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
if (overrideValue || (currentEntry && new Date(currentEntry.createdAt).getTime() + expiryTime <= Date.now())) {
|
|
137
118
|
await tx.run(
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
119
|
+
UPDATE.entity(configInstance.tableNameEventLock)
|
|
120
|
+
.set({
|
|
121
|
+
createdAt: new Date().toISOString(),
|
|
122
|
+
value,
|
|
123
|
+
})
|
|
124
|
+
.where("code =", currentEntry.code)
|
|
142
125
|
);
|
|
143
126
|
result = true;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
if (!overrideValue) {
|
|
148
|
-
currentEntry = await tx.run(
|
|
149
|
-
SELECT.one
|
|
150
|
-
.from(configInstance.tableNameEventLock)
|
|
151
|
-
.forUpdate({ wait: config.getConfigInstance().forUpdateTimeout })
|
|
152
|
-
.where("code =", fullKey)
|
|
153
|
-
);
|
|
154
|
-
}
|
|
155
|
-
if (
|
|
156
|
-
overrideValue ||
|
|
157
|
-
(currentEntry &&
|
|
158
|
-
new Date(currentEntry.createdAt).getTime() + expiryTime <=
|
|
159
|
-
Date.now())
|
|
160
|
-
) {
|
|
161
|
-
await tx.run(
|
|
162
|
-
UPDATE.entity(configInstance.tableNameEventLock)
|
|
163
|
-
.set({
|
|
164
|
-
createdAt: new Date().toISOString(),
|
|
165
|
-
value,
|
|
166
|
-
})
|
|
167
|
-
.where("code =", currentEntry.code)
|
|
168
|
-
);
|
|
169
|
-
result = true;
|
|
170
|
-
} else {
|
|
171
|
-
result = false;
|
|
172
|
-
}
|
|
127
|
+
} else {
|
|
128
|
+
result = false;
|
|
173
129
|
}
|
|
174
130
|
}
|
|
175
|
-
);
|
|
131
|
+
});
|
|
176
132
|
return result;
|
|
177
133
|
};
|
|
178
134
|
|
package/src/shared/redis.js
CHANGED
|
@@ -15,9 +15,7 @@ const createMainClientAndConnect = () => {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
const errorHandlerCreateClient = (err) => {
|
|
18
|
-
cds
|
|
19
|
-
.log(COMPONENT_NAME)
|
|
20
|
-
.error("error from redis client for pub/sub failed", err);
|
|
18
|
+
cds.log(COMPONENT_NAME).error("error from redis client for pub/sub failed", err);
|
|
21
19
|
subscriberClientPromise = null;
|
|
22
20
|
setTimeout(createMainClientAndConnect, 5 * 1000).unref();
|
|
23
21
|
};
|