@itentialopensource/adapter-kafkav2 0.3.13 → 0.3.15
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/CHANGELOG.md +16 -0
- package/README.md +62 -1
- package/adapter.js +52 -44
- package/package.json +1 -1
- package/pronghorn.json +1 -3
- package/refs?service=git-upload-pack +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,20 @@
|
|
|
1
1
|
|
|
2
|
+
## 0.3.15 [02-17-2023]
|
|
3
|
+
|
|
4
|
+
* Updated readme
|
|
5
|
+
|
|
6
|
+
See merge request itentialopensource/adapters/notification-messaging/adapter-kafkav2!2
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 0.3.14 [02-16-2023]
|
|
11
|
+
|
|
12
|
+
* updated to allow multiple subscribers per topic entry and fixed partition logic
|
|
13
|
+
|
|
14
|
+
See merge request itentialopensource/adapters/notification-messaging/adapter-kafkav2!1
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
2
18
|
## 0.3.13 [02-07-2023]
|
|
3
19
|
|
|
4
20
|
* Bug fixes and performance improvements
|
package/README.md
CHANGED
|
@@ -148,9 +148,66 @@ Example of adapter's configuration with filtering applied:
|
|
|
148
148
|
}
|
|
149
149
|
],
|
|
150
150
|
```
|
|
151
|
-
|
|
152
151
|
When operator skips to provide `filters` property or the property contains no actual filters set, then all messages are passed.
|
|
153
152
|
|
|
153
|
+
Example of adapter's configuration with multiple paritions and subscribers per topic:
|
|
154
|
+
```json
|
|
155
|
+
"topics": [
|
|
156
|
+
{
|
|
157
|
+
"name": "topic1",
|
|
158
|
+
"always": true,
|
|
159
|
+
"partition": 0,
|
|
160
|
+
"subscriberInfo": [
|
|
161
|
+
{
|
|
162
|
+
"subname": "default",
|
|
163
|
+
"filters": [
|
|
164
|
+
"PIXI",
|
|
165
|
+
"DRED",
|
|
166
|
+
"F: (\\w+), L: (\\w+)",
|
|
167
|
+
"\\d{3,4}"
|
|
168
|
+
],
|
|
169
|
+
"rabbit": "topic1",
|
|
170
|
+
"throttle": {}
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
"subname": "sub2",
|
|
174
|
+
"filters": [
|
|
175
|
+
"[abc]",
|
|
176
|
+
"F: (\\w+), L: (\\w+)",
|
|
177
|
+
"\\d{3,4}"
|
|
178
|
+
],
|
|
179
|
+
"rabbit": "topic1-s2",
|
|
180
|
+
"throttle": {}
|
|
181
|
+
}
|
|
182
|
+
]
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
"name": "topic1",
|
|
186
|
+
"always": true,
|
|
187
|
+
"partition": 1,
|
|
188
|
+
"subscriberInfo": [
|
|
189
|
+
{
|
|
190
|
+
"subname": "default",
|
|
191
|
+
"filters": [
|
|
192
|
+
"PIXI",
|
|
193
|
+
"DRED",
|
|
194
|
+
"[abc]",
|
|
195
|
+
"F: (\\w+), L: (\\w+)",
|
|
196
|
+
"\\d{3,4}"
|
|
197
|
+
],
|
|
198
|
+
"rabbit": "topic1-p1",
|
|
199
|
+
"throttle": {}
|
|
200
|
+
}
|
|
201
|
+
]
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
"name": "test-6",
|
|
205
|
+
"always": true
|
|
206
|
+
}
|
|
207
|
+
],
|
|
208
|
+
```
|
|
209
|
+
Note that if no parition is supplied only messages on partition 0 will be consumed. Additionally, if no rabbit topic is supplied, events will be published to a topic with the same name as the Kafka topic. For example, topic `test-6` above will be published to the `test-6` rabbit topic.
|
|
210
|
+
|
|
154
211
|
### Connection Properties
|
|
155
212
|
|
|
156
213
|
These base properties are used to connect to Kafka upon the adapter initially coming up. It is important to set these properties appropriately.
|
|
@@ -211,6 +268,10 @@ The following properties are used to define the Kafka Consumer. These properties
|
|
|
211
268
|
| encoding | If set to 'buffer', values will be returned as raw buffer objects..|
|
|
212
269
|
| keyEncoding | |
|
|
213
270
|
|
|
271
|
+
## Parsing Properties
|
|
272
|
+
|
|
273
|
+
The `parseMessage` property allows the user to define how they want the Kafka message to be published to IAP's event system. If `parseMessage` is set to true or omitted, the value of the Kafka message will be parsed as either an object or string and wrapped in an outer object. The wrapper object's key can be defined with the property `wrapMessage`, or the default value `payload` can be used if omitted. If `parseMessage` is set to false, the entire kafka payload, including metadata, would be returned and the message itself would need to be transformed at a later point.
|
|
274
|
+
|
|
214
275
|
## Testing an Itential Product Adapter
|
|
215
276
|
|
|
216
277
|
Mocha is generally used to test all Itential Product Adapters. There are unit tests as well as integration tests performed. Integration tests can generally be run as standalone using mock data and running the adapter in stub mode, or as integrated. When running integrated, every effort is made to prevent environmental failures, however there is still a possibility.
|
package/adapter.js
CHANGED
|
@@ -217,7 +217,7 @@ class Kafkav2 extends EventEmitterCl {
|
|
|
217
217
|
{
|
|
218
218
|
subname: 'default',
|
|
219
219
|
filters: [],
|
|
220
|
-
rabbit:
|
|
220
|
+
rabbit: this.topicsEvents[t].topic,
|
|
221
221
|
throttle: {}
|
|
222
222
|
}
|
|
223
223
|
];
|
|
@@ -260,7 +260,7 @@ class Kafkav2 extends EventEmitterCl {
|
|
|
260
260
|
{
|
|
261
261
|
subname: 'default',
|
|
262
262
|
filters: [],
|
|
263
|
-
rabbit:
|
|
263
|
+
rabbit: this.props.topics[t].name,
|
|
264
264
|
throttle: {}
|
|
265
265
|
}
|
|
266
266
|
];
|
|
@@ -293,7 +293,7 @@ class Kafkav2 extends EventEmitterCl {
|
|
|
293
293
|
// check to see if we need to add a subscriber
|
|
294
294
|
for (let sub = 0; sub < subInfo.length; sub += 1) {
|
|
295
295
|
let subFound = false;
|
|
296
|
-
for (let s = 0; s
|
|
296
|
+
for (let s = 0; s < this.topicsEvents[te].subInfo.length; s += 1) {
|
|
297
297
|
// if the subscriber is found, no need to add anything
|
|
298
298
|
if (subInfo[sub].subname === this.topicsEvents[te].subInfo[s].subname) {
|
|
299
299
|
subFound = true;
|
|
@@ -407,13 +407,13 @@ class Kafkav2 extends EventEmitterCl {
|
|
|
407
407
|
try {
|
|
408
408
|
// Create a kafka client
|
|
409
409
|
const combinedProps = this.props.client || {};
|
|
410
|
-
if (this.props.client.ssl.ca) {
|
|
410
|
+
if (this.props.client.ssl && this.props.client.ssl.ca) {
|
|
411
411
|
combinedProps.ssl.ca = [fs.readFileSync(this.props.client.ssl.ca, 'utf-8')];
|
|
412
412
|
}
|
|
413
|
-
if (this.props.client.ssl.cert) {
|
|
413
|
+
if (this.props.client.ssl && this.props.client.ssl.cert) {
|
|
414
414
|
combinedProps.ssl.cert = fs.readFileSync(this.props.client.ssl.cert, 'utf-8');
|
|
415
415
|
}
|
|
416
|
-
if (this.props.client.ssl.key) {
|
|
416
|
+
if (this.props.client.ssl && this.props.client.ssl.key) {
|
|
417
417
|
combinedProps.ssl.key = fs.readFileSync(this.props.client.ssl.key, 'utf-8');
|
|
418
418
|
}
|
|
419
419
|
|
|
@@ -423,22 +423,18 @@ class Kafkav2 extends EventEmitterCl {
|
|
|
423
423
|
|
|
424
424
|
this.consumer = this.KafkaClient.consumer(this.props.consumer || {});
|
|
425
425
|
|
|
426
|
-
const isPassingFiltering = (topic, message) => {
|
|
426
|
+
const isPassingFiltering = (topic, message, filters) => {
|
|
427
427
|
const topicConfig = this.topicsEvents.find((e) => e.topic === topic);
|
|
428
428
|
|
|
429
429
|
if (!topicConfig) return true;
|
|
430
430
|
|
|
431
431
|
if (!topicConfig.subInfo || !Array.isArray(topicConfig.subInfo)) return true;
|
|
432
|
-
|
|
433
|
-
const
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
if (message.value.toString().match(re)) {
|
|
439
|
-
log.debug('Matched filter: ', re);
|
|
440
|
-
return true;
|
|
441
|
-
}
|
|
432
|
+
if (filters.length === 0) return true;
|
|
433
|
+
const matched = filters.find((filter) => {
|
|
434
|
+
const re = new RegExp(filter);
|
|
435
|
+
if (message.value.toString().match(re)) {
|
|
436
|
+
log.debug('Matched filter: ', re);
|
|
437
|
+
return true;
|
|
442
438
|
}
|
|
443
439
|
return false;
|
|
444
440
|
});
|
|
@@ -463,27 +459,8 @@ class Kafkav2 extends EventEmitterCl {
|
|
|
463
459
|
log.info(`PROCESSING NEW MESSAGE ON TOPIC: ${topic} PARTITION: ${partition} WITH OFFSET: ${message.offset}`);
|
|
464
460
|
const newMsg = message;
|
|
465
461
|
let avroUsed = false;
|
|
466
|
-
let desiredTopic =
|
|
467
|
-
|
|
468
|
-
// find the topic here to change the offset
|
|
469
|
-
for (let t = 0; t < this.topicsEvents.length; t += 1) {
|
|
470
|
-
if (this.topicsEvents[t].topic === topic && this.topicsEvents[t].partition === partition) {
|
|
471
|
-
if (this.topicsEvents[t].offset < message.offset) {
|
|
472
|
-
this.topicsEvents[t].offset = message.offset;
|
|
473
|
-
}
|
|
474
|
-
// determine if we are using AVRO and set flag
|
|
475
|
-
if (this.topicsEvents[t].avro && this.topicsEvents[t].avro.toUpperCase() === 'YES') {
|
|
476
|
-
avroUsed = true;
|
|
477
|
-
}
|
|
478
|
-
// set desired topic
|
|
479
|
-
if (this.topicsEvents[t].subInfo && this.topicsEvents[t].subInfo.rabbit) {
|
|
480
|
-
desiredTopic = this.topicsEvents[t].subInfo.rabbit;
|
|
481
|
-
} else {
|
|
482
|
-
desiredTopic = this.topicsEvents[t].topic;
|
|
483
|
-
}
|
|
484
|
-
break;
|
|
485
|
-
}
|
|
486
|
-
}
|
|
462
|
+
let desiredTopic = [];
|
|
463
|
+
let allowedPartition = false;
|
|
487
464
|
|
|
488
465
|
// if using avro
|
|
489
466
|
if (this.registry && avroUsed) {
|
|
@@ -514,18 +491,45 @@ class Kafkav2 extends EventEmitterCl {
|
|
|
514
491
|
}
|
|
515
492
|
}, fastInt);
|
|
516
493
|
}
|
|
494
|
+
// find the topic here to change the offset
|
|
495
|
+
for (let t = 0; t < this.topicsEvents.length; t += 1) {
|
|
496
|
+
if (this.topicsEvents[t].topic === topic && this.topicsEvents[t].partition === partition) {
|
|
497
|
+
allowedPartition = true;
|
|
498
|
+
if (this.topicsEvents[t].offset < message.offset) {
|
|
499
|
+
this.topicsEvents[t].offset = message.offset;
|
|
500
|
+
}
|
|
501
|
+
// determine if we are using AVRO and set flag
|
|
502
|
+
if (this.topicsEvents[t].avro && this.topicsEvents[t].avro.toUpperCase() === 'YES') {
|
|
503
|
+
avroUsed = true;
|
|
504
|
+
}
|
|
505
|
+
// set desired topic for messages passing filtering
|
|
506
|
+
if (this.topicsEvents[t].subInfo) {
|
|
507
|
+
for (let k = 0; k < this.topicsEvents[t].subInfo.length; k += 1) {
|
|
508
|
+
let passesFiltering = true;
|
|
509
|
+
if (this.topicsEvents[t].subInfo[k].filters) {
|
|
510
|
+
passesFiltering = isPassingFiltering(topic, newMsg, this.topicsEvents[t].subInfo[k].filters);
|
|
511
|
+
}
|
|
512
|
+
if (this.topicsEvents[t].subInfo[k].rabbit && passesFiltering) {
|
|
513
|
+
desiredTopic.push(this.topicsEvents[t].subInfo[k].rabbit);
|
|
514
|
+
} else if (passesFiltering) {
|
|
515
|
+
desiredTopic.push(this.topicsEvents[t].topic);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
break;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
517
522
|
|
|
518
|
-
|
|
519
|
-
if (goodMsg) {
|
|
523
|
+
if (desiredTopic.length !== 0 && allowedPartition) {
|
|
520
524
|
log.info(`Message: '${message.value.toString()}' being CONSUMED as it does meet the filter condition`);
|
|
521
|
-
if (mytopics.includes(
|
|
525
|
+
if (desiredTopic.every((val) => mytopics.includes(val))) {
|
|
522
526
|
log.info(`Emitting: ${message.value.toString()} TO ${desiredTopic}`);
|
|
523
527
|
} else {
|
|
524
528
|
log.info(`The desired topic ${desiredTopic} does not exist. If it should, make sure it is in pronghorn.json`);
|
|
525
529
|
log.info(`Emitting: ${newMsg.value.toString()} TO kafka`);
|
|
526
530
|
desiredTopic = 'kafka';
|
|
527
531
|
}
|
|
528
|
-
if (this.props.parseMessage) {
|
|
532
|
+
if (this.props.parseMessage || this.props.parseMessage === undefined) {
|
|
529
533
|
let messageObj;
|
|
530
534
|
const wrapper = this.props.wrapMessage || 'payload';
|
|
531
535
|
try {
|
|
@@ -533,9 +537,13 @@ class Kafkav2 extends EventEmitterCl {
|
|
|
533
537
|
} catch (ex) {
|
|
534
538
|
messageObj = { [wrapper]: newMsg.value.toString() };
|
|
535
539
|
}
|
|
536
|
-
|
|
540
|
+
for (let j = 0; j < desiredTopic.length; j += 1) {
|
|
541
|
+
eventSystem.publish(desiredTopic[j], messageObj);
|
|
542
|
+
}
|
|
537
543
|
} else {
|
|
538
|
-
|
|
544
|
+
for (let j = 0; j < desiredTopic.length; j += 1) {
|
|
545
|
+
eventSystem.publish(desiredTopic[j], newMsg);
|
|
546
|
+
}
|
|
539
547
|
}
|
|
540
548
|
} else {
|
|
541
549
|
log.info(`Message: '${newMsg.value.toString()}' being DROPPED as it fails to meet any filter condition`);
|
package/package.json
CHANGED
package/pronghorn.json
CHANGED
|
Binary file
|