@cap-js-community/event-queue 1.3.6 → 1.4.1

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.
@@ -12,7 +12,7 @@ let mainClientPromise;
12
12
  const subscriberChannelClientPromise = {};
13
13
  let lastErrorLog = Date.now();
14
14
 
15
- const createMainClientAndConnect = () => {
15
+ const createMainClientAndConnect = (options) => {
16
16
  if (mainClientPromise) {
17
17
  return mainClientPromise;
18
18
  }
@@ -20,14 +20,14 @@ const createMainClientAndConnect = () => {
20
20
  const errorHandlerCreateClient = (err) => {
21
21
  cds.log(COMPONENT_NAME).error("error from redis client for pub/sub failed", err);
22
22
  mainClientPromise = null;
23
- setTimeout(createMainClientAndConnect, LOG_AFTER_SEC * 1000).unref();
23
+ setTimeout(() => createMainClientAndConnect(options), LOG_AFTER_SEC * 1000).unref();
24
24
  };
25
25
 
26
- mainClientPromise = createClientAndConnect(errorHandlerCreateClient);
26
+ mainClientPromise = createClientAndConnect(options, errorHandlerCreateClient);
27
27
  return mainClientPromise;
28
28
  };
29
29
 
30
- const _createClientBase = () => {
30
+ const _createClientBase = (redisOptions) => {
31
31
  const env = getEnvInstance();
32
32
  try {
33
33
  const credentials = env.getRedisCredentialsFromEnv();
@@ -40,18 +40,19 @@ const _createClientBase = () => {
40
40
  defaults: {
41
41
  password: credentials.password,
42
42
  socket: { tls: credentials.tls },
43
+ ...redisOptions,
43
44
  },
44
45
  });
45
46
  }
46
- return redis.createClient({ url });
47
+ return redis.createClient({ url, ...redisOptions });
47
48
  } catch (err) {
48
49
  throw EventQueueError.redisConnectionFailure(err);
49
50
  }
50
51
  };
51
52
 
52
- const createClientAndConnect = async (errorHandlerCreateClient) => {
53
+ const createClientAndConnect = async (options, errorHandlerCreateClient) => {
53
54
  try {
54
- const client = _createClientBase();
55
+ const client = _createClientBase(options);
55
56
  await client.connect();
56
57
  client.on("error", (err) => {
57
58
  const dateNow = Date.now();
@@ -74,14 +75,14 @@ const createClientAndConnect = async (errorHandlerCreateClient) => {
74
75
  }
75
76
  };
76
77
 
77
- const subscribeRedisChannel = (channel, subscribeHandler) => {
78
+ const subscribeRedisChannel = (options, channel, subscribeHandler) => {
78
79
  const errorHandlerCreateClient = (err) => {
79
80
  cds.log(COMPONENT_NAME).error(`error from redis client for pub/sub failed for channel ${channel}`, err);
80
81
  subscriberChannelClientPromise[channel] = null;
81
- setTimeout(() => subscribeRedisChannel(channel, subscribeHandler), LOG_AFTER_SEC * 1000).unref();
82
+ setTimeout(() => subscribeRedisChannel(options, channel, subscribeHandler), LOG_AFTER_SEC * 1000).unref();
82
83
  };
83
84
 
84
- subscriberChannelClientPromise[channel] = createClientAndConnect(errorHandlerCreateClient)
85
+ subscriberChannelClientPromise[channel] = createClientAndConnect(options, errorHandlerCreateClient)
85
86
  .then((client) => {
86
87
  cds.log(COMPONENT_NAME).info("subscribe redis client connected channel", { channel });
87
88
  client.subscribe(channel, subscribeHandler).catch(errorHandlerCreateClient);
@@ -93,8 +94,8 @@ const subscribeRedisChannel = (channel, subscribeHandler) => {
93
94
  });
94
95
  };
95
96
 
96
- const publishMessage = async (channel, message) => {
97
- const client = await createMainClientAndConnect();
97
+ const publishMessage = async (options, channel, message) => {
98
+ const client = await createMainClientAndConnect(options);
98
99
  return await client.publish(channel, message);
99
100
  };
100
101
 
@@ -116,9 +117,9 @@ const _resilientClientClose = async (client) => {
116
117
  }
117
118
  };
118
119
 
119
- const connectionCheck = async () => {
120
+ const connectionCheck = async (options) => {
120
121
  return new Promise((resolve, reject) => {
121
- createClientAndConnect(reject)
122
+ createClientAndConnect(options, reject)
122
123
  .then((client) => {
123
124
  if (client) {
124
125
  _resilientClientClose(client);
@@ -1,170 +0,0 @@
1
- "use strict";
2
-
3
- const { promisify } = require("util");
4
-
5
- const cds = require("@sap/cds");
6
-
7
- const redis = require("./shared/redis");
8
- const { checkLockExistsAndReturnValue } = require("./shared/distributedLock");
9
- const config = require("./config");
10
- const runner = require("./runner");
11
- const { getSubdomainForTenantId } = require("./shared/cdsHelper");
12
-
13
- const EVENT_MESSAGE_CHANNEL = "EVENT_QUEUE_MESSAGE_CHANNEL";
14
- const COMPONENT_NAME = "/eventQueue/redisPubSub";
15
- const TRIES_FOR_PUBLISH_PERIODIC_EVENT = 10;
16
- const SLEEP_TIME_FOR_PUBLISH_PERIODIC_EVENT = 30 * 1000;
17
-
18
- const wait = promisify(setTimeout);
19
- let subscriberClientPromise;
20
-
21
- const initEventQueueRedisSubscribe = () => {
22
- if (subscriberClientPromise || !config.redisEnabled) {
23
- return;
24
- }
25
- redis.subscribeRedisChannel(EVENT_MESSAGE_CHANNEL, _messageHandlerProcessEvents);
26
- };
27
-
28
- const _messageHandlerProcessEvents = async (messageData) => {
29
- const logger = cds.log(COMPONENT_NAME);
30
- try {
31
- const { tenantId, type, subType } = JSON.parse(messageData);
32
- logger.debug("received redis event", {
33
- tenantId,
34
- type,
35
- subType,
36
- });
37
- if (!config.isEventQueueActive) {
38
- cds.log(COMPONENT_NAME).info("Skipping processing because runner is deactivated!", {
39
- type,
40
- subType,
41
- });
42
- return;
43
- }
44
-
45
- const subdomain = await getSubdomainForTenantId(tenantId);
46
- const user = new cds.User.Privileged(config.userId);
47
- const tenantContext = {
48
- tenant: tenantId,
49
- user,
50
- // NOTE: we need this because of logging otherwise logs would not contain the subdomain
51
- http: { req: { authInfo: { getSubdomain: () => subdomain } } },
52
- };
53
-
54
- if (!config.getEventConfig(type, subType)) {
55
- if (config.isCapOutboxEvent(type)) {
56
- try {
57
- const service = await cds.connect.to(subType);
58
- cds.outboxed(service);
59
- } catch (err) {
60
- logger.error("could not connect to outboxed service", err, {
61
- type,
62
- subType,
63
- });
64
- return;
65
- }
66
- } else {
67
- logger.error("cannot find configuration for published event. Event won't be processed", {
68
- type,
69
- subType,
70
- });
71
- return;
72
- }
73
- }
74
-
75
- return await cds.tx(tenantContext, async ({ context }) => {
76
- return await runner.runEventCombinationForTenant(context, type, subType);
77
- });
78
- } catch (err) {
79
- logger.error("could not parse event information", {
80
- messageData,
81
- });
82
- }
83
- };
84
-
85
- const broadcastEvent = async (tenantId, type, subType) => {
86
- const logger = cds.log(COMPONENT_NAME);
87
- try {
88
- if (!config.isEventQueueActive) {
89
- cds.log(COMPONENT_NAME).info("Skipping processing because runner is deactivated!", {
90
- type,
91
- subType,
92
- });
93
- return;
94
- }
95
- if (!config.redisEnabled) {
96
- if (config.registerAsEventProcessor) {
97
- let context = {};
98
- if (tenantId) {
99
- const subdomain = await getSubdomainForTenantId(tenantId);
100
- const user = new cds.User.Privileged(config.userId);
101
- context = {
102
- // NOTE: we need this because of logging otherwise logs would not contain the subdomain
103
- tenant: tenantId,
104
- user,
105
- http: { req: { authInfo: { getSubdomain: () => subdomain } } },
106
- };
107
- }
108
-
109
- return await cds.tx(context, async ({ context }) => {
110
- return await runner.runEventCombinationForTenant(context, type, subType);
111
- });
112
- }
113
- return;
114
- }
115
- const eventConfig = config.getEventConfig(type, subType);
116
- for (let i = 0; i < TRIES_FOR_PUBLISH_PERIODIC_EVENT; i++) {
117
- const result = await checkLockExistsAndReturnValue(
118
- new cds.EventContext({ tenant: tenantId }),
119
- [type, subType].join("##")
120
- );
121
- if (result) {
122
- logger.debug("skip publish redis event as no lock is available", {
123
- type,
124
- subType,
125
- index: i,
126
- isPeriodic: eventConfig.isPeriodic,
127
- waitInterval: SLEEP_TIME_FOR_PUBLISH_PERIODIC_EVENT,
128
- });
129
- if (!eventConfig.isPeriodic) {
130
- break;
131
- }
132
- await wait(SLEEP_TIME_FOR_PUBLISH_PERIODIC_EVENT);
133
- continue;
134
- }
135
- logger.debug("publishing redis event", {
136
- tenantId,
137
- type,
138
- subType,
139
- });
140
- await redis.publishMessage(EVENT_MESSAGE_CHANNEL, JSON.stringify({ tenantId, type, subType }));
141
- break;
142
- }
143
- } catch (err) {
144
- logger.error("publish event failed!", err, {
145
- tenantId,
146
- type,
147
- subType,
148
- });
149
- }
150
- };
151
-
152
- const closeSubscribeClient = async () => {
153
- try {
154
- const client = await subscriberClientPromise;
155
- if (client?.quit) {
156
- await client.quit();
157
- }
158
- } catch (err) {
159
- // ignore errors during shutdown
160
- }
161
- };
162
-
163
- module.exports = {
164
- initEventQueueRedisSubscribe,
165
- broadcastEvent,
166
- closeSubscribeClient,
167
- __: {
168
- _messageHandlerProcessEvents,
169
- },
170
- };