@cap-js-community/event-queue 1.10.8 → 1.10.9

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cap-js-community/event-queue",
3
- "version": "1.10.8",
3
+ "version": "1.10.9",
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",
@@ -40,23 +40,17 @@ const getOpenQueueEntries = async (tx, filterAppSpecificEvents = true) => {
40
40
  const [srvName, actionName] = subType.split(".");
41
41
  try {
42
42
  const service = await cds.connect.to(srvName);
43
- if (!filterAppSpecificEvents) {
44
- return; // will be done in finally
45
- }
46
-
47
- if (!service) {
48
- return;
49
- }
50
- cds.outboxed(service);
51
- if (actionName) {
52
- config.addCAPOutboxEventSpecificAction(srvName, actionName);
53
- }
54
43
  if (filterAppSpecificEvents) {
44
+ if (!service) {
45
+ continue;
46
+ }
47
+ cds.outboxed(service);
48
+ if (actionName) {
49
+ config.addCAPOutboxEventSpecificAction(srvName, actionName);
50
+ }
55
51
  if (eventConfig.shouldBeProcessedInThisApplication(type, subType)) {
56
52
  result.push({ type, subType });
57
53
  }
58
- } else {
59
- result.push({ type, subType });
60
54
  }
61
55
  } catch {
62
56
  /* ignore catch */
@@ -150,7 +150,9 @@ const getAllTenantIds = async () => {
150
150
  }, []);
151
151
  };
152
152
 
153
- const getAllTenantWithSubdomain = async () => {
153
+ const TENANT_COLUMNS = ["subscribedSubdomain", "createdAt", "modifiedAt"];
154
+
155
+ const getAllTenantWithMetadata = async () => {
154
156
  const response = await _getAllTenantBase();
155
157
  if (!response) {
156
158
  return null;
@@ -160,10 +162,19 @@ const getAllTenantWithSubdomain = async () => {
160
162
  const tenantId = row.subscribedTenantId ?? row.tenant;
161
163
  result = await result;
162
164
  if (await common.isTenantIdValidCb(TenantIdCheckTypes.eventProcessing, tenantId)) {
163
- result.push({
164
- ID: tenantId,
165
- subdomain: row.subscribedSubdomain,
166
- });
165
+ const data = Object.entries(row).reduce(
166
+ (result, [key, value]) => {
167
+ if (TENANT_COLUMNS.includes(key)) {
168
+ result[key] = value;
169
+ } else {
170
+ result.metadata[key] = value;
171
+ }
172
+ return result;
173
+ },
174
+ { metadata: {} }
175
+ );
176
+ data.metadata = JSON.stringify(data.metadata);
177
+ result.push(data);
167
178
  }
168
179
  return result;
169
180
  }, []);
@@ -172,5 +183,5 @@ const getAllTenantWithSubdomain = async () => {
172
183
  module.exports = {
173
184
  executeInNewTransaction,
174
185
  getAllTenantIds,
175
- getAllTenantWithSubdomain,
186
+ getAllTenantWithMetadata,
176
187
  };
@@ -121,8 +121,9 @@ const _checkLockExistsDb = async (context, fullKey) => {
121
121
 
122
122
  const _releaseLockRedis = async (context, fullKey) => {
123
123
  const client = await redis.createMainClientAndConnect(config.redisOptions);
124
- await client.del(fullKey);
124
+ const result = await client.del(fullKey);
125
125
  delete existingLocks[fullKey];
126
+ return result === 1;
126
127
  };
127
128
 
128
129
  const _releaseLockDb = async (context, fullKey) => {
@@ -130,6 +131,7 @@ const _releaseLockDb = async (context, fullKey) => {
130
131
  await tx.run(DELETE.from(config.tableNameEventLock).where("code =", fullKey));
131
132
  });
132
133
  delete existingLocks[fullKey];
134
+ return true;
133
135
  };
134
136
 
135
137
  const _acquireLockDB = async (
@@ -13,14 +13,14 @@ service EventQueueAdminService {
13
13
  null as space: String,
14
14
  *
15
15
  } actions {
16
- action setStatusAndAttempts(
17
- // TODO: remove tenant as soon as CAP issue is fixed https://github.tools.sap/cap/issues/issues/18445
18
- @mandatory
19
- tenant: String,
20
- status: db.Status,
21
- @assert.range: [0,100]
22
- attempts: Integer) returns Event;
23
- }
16
+ action setStatusAndAttempts(
17
+ // TODO: remove tenant as soon as CAP issue is fixed https://github.tools.sap/cap/issues/issues/18445
18
+ @mandatory
19
+ tenant: String,
20
+ status: db.Status,
21
+ @assert.range: [0,100]
22
+ attempts: Integer) returns Event;
23
+ }
24
24
 
25
25
  @cds.persistence.skip
26
26
  @readonly
@@ -32,12 +32,22 @@ service EventQueueAdminService {
32
32
  space: String;
33
33
  ttl: Integer;
34
34
  createdAt: Integer;
35
- }
35
+ } actions {
36
+ action releaseLock(
37
+ // TODO: remove tenant as soon as CAP issue is fixed https://github.tools.sap/cap/issues/issues/18445
38
+ @mandatory
39
+ tenant: String,
40
+ @mandatory
41
+ type: String,
42
+ @mandatory
43
+ subType: String) returns Boolean;
44
+ }
36
45
 
37
46
  @readonly
38
47
  @cds.persistence.skip
39
48
  entity Tenant {
40
49
  Key ID: String;
41
50
  subdomain: String;
51
+ metadata: String;
42
52
  }
43
53
  }
@@ -5,6 +5,7 @@ const cdsHelper = require("../../src/shared/cdsHelper");
5
5
  const { EventProcessingStatus } = require("../../src");
6
6
  const config = require("../../src/config");
7
7
  const distributedLock = require("../../src/shared/distributedLock");
8
+ const redisPub = require("../../src/redis/redisPub");
8
9
 
9
10
  module.exports = class AdminService extends cds.ApplicationService {
10
11
  async init() {
@@ -61,7 +62,7 @@ module.exports = class AdminService extends cds.ApplicationService {
61
62
  });
62
63
 
63
64
  this.on("READ", Tenant, async () => {
64
- const tenants = await cdsHelper.getAllTenantWithSubdomain();
65
+ const tenants = await cdsHelper.getAllTenantWithMetadata();
65
66
  return tenants ?? [];
66
67
  });
67
68
 
@@ -82,14 +83,27 @@ module.exports = class AdminService extends cds.ApplicationService {
82
83
  return req.reject(400, "No status or attempts provided");
83
84
  }
84
85
 
85
- await cds.tx({ tenant, headers: { "z-id": tenant } }, async () => {
86
+ const event = await cds.tx({ tenant, headers: { "z-id": tenant } }, async () => {
87
+ const event = await SELECT.one.from(EventDb).where({ ID: req.params[0].ID ?? req.params[0] });
86
88
  await UPDATE.entity(EventDb)
87
89
  .set(updateData)
88
90
  .where({ ID: req.params[0].ID ?? req.params[0] });
91
+ return event;
92
+ });
93
+ redisPub.broadcastEvent(tenant, event).catch(() => {
94
+ /* ignore errors */
89
95
  });
90
96
  return await this.send(new cds.Request({ query: req.query, headers: req.headers }));
91
97
  });
92
98
 
99
+ this.on("releaseLock", async (req) => {
100
+ cds.log("eventQueue").info("Releasing event-queue lock", req.data);
101
+ const { tenant, type, subType } = req.data;
102
+ return await cds.tx({ tenant }, async (tx) => {
103
+ return await distributedLock.releaseLock(tx.context, [type, subType].join("##"));
104
+ });
105
+ });
106
+
93
107
  await super.init();
94
108
  }
95
109