kafka-crab-js 0.0.3 → 0.0.10
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/Cargo.toml +13 -5
- package/README.md +68 -7
- package/example/sample.mjs +12 -8
- package/index.d.ts +9 -8
- package/index.js +1 -2
- package/package.json +13 -4
- package/src/kafka/kafka_client.rs +15 -18
- package/src/kafka/kafka_consumer.rs +8 -6
package/Cargo.toml
CHANGED
|
@@ -8,16 +8,24 @@ crate-type = ["cdylib"]
|
|
|
8
8
|
|
|
9
9
|
[dependencies]
|
|
10
10
|
# Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix
|
|
11
|
-
napi = { version = "2.13", default-features = false, features = [
|
|
11
|
+
napi = { version = "2.13", default-features = false, features = [
|
|
12
|
+
"napi4",
|
|
13
|
+
"tokio_rt",
|
|
14
|
+
] }
|
|
12
15
|
napi-derive = "2.13"
|
|
13
16
|
|
|
14
|
-
anyhow = { version= "1.0", features = ["backtrace"]}
|
|
17
|
+
anyhow = { version = "1.0", features = ["backtrace"] }
|
|
15
18
|
|
|
16
|
-
rdkafka = { version = "0.32", features = [
|
|
19
|
+
rdkafka = { version = "0.32", features = [
|
|
20
|
+
"libz-static",
|
|
21
|
+
"cmake-build",
|
|
22
|
+
"tokio",
|
|
23
|
+
"ssl-vendored",
|
|
24
|
+
] }
|
|
17
25
|
tokio = { version = "1", features = ["full"] }
|
|
18
26
|
|
|
19
|
-
tracing
|
|
20
|
-
tracing-subscriber = "0.3"
|
|
27
|
+
tracing = "0.1"
|
|
28
|
+
tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] }
|
|
21
29
|
|
|
22
30
|
[build-dependencies]
|
|
23
31
|
napi-build = "2.0.1"
|
package/README.md
CHANGED
|
@@ -1,16 +1,77 @@
|
|
|
1
|
-
Kafka Crab Js
|
|
2
|
-
-------------
|
|
1
|
+
# Kafka Crab Js
|
|
3
2
|
|
|
4
3
|
**Blazingly Fast Kafka Client for NodeJs**
|
|
5
4
|
|
|
6
5
|
Kafka-Crab-JS is a powerful Node.js library that allows developers to interact with Apache Kafka using Rust programming language, seamlessly integrated with Node.js applications. This documentation provides an overview of the Kafka-Crab-JS library, including installation instructions, usage guidelines, and examples.
|
|
7
6
|
|
|
7
|
+
The plugin can be found on [npm](https://www.npmjs.com/package/kafka-crab-js) and the source code is available on [GitHub](https://github.com/inaiat/kafka-crab-js).
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## Table of Contents
|
|
10
|
+
1. [Installation](#installation)
|
|
11
|
+
2. [Usage](#usage)
|
|
12
|
+
- [Client](#client)
|
|
13
|
+
- [Producer](#producer)
|
|
14
|
+
- [Consumer](#consumer)
|
|
15
|
+
3. [Examples](#examples)
|
|
10
16
|
|
|
11
|
-
To use Kafka-Crab-JS in your Node.js project, follow the steps below:
|
|
12
17
|
|
|
13
|
-
|
|
18
|
+
## Installation
|
|
19
|
+
To use Kafka Crab JS, you need to have Node.js and npm (Node Package Manager) installed on your system. Once you have them set up, you can install the plugin by running the following command:
|
|
14
20
|
|
|
15
|
-
|
|
16
|
-
|
|
21
|
+
```shell
|
|
22
|
+
npm install kafka-crab-js
|
|
23
|
+
```
|
|
24
|
+
## Usage
|
|
25
|
+
### Client
|
|
26
|
+
Creating a Client Instance
|
|
27
|
+
Next, you can create a client instance by specifying the Kafka broker(s) and other optional configurations:
|
|
28
|
+
|
|
29
|
+
```javascript
|
|
30
|
+
import { KafkaClient }
|
|
31
|
+
|
|
32
|
+
const kafkaClient = new KafkaClient({
|
|
33
|
+
brokers: 'localhost:29092',
|
|
34
|
+
clientId: 'my-id'});
|
|
35
|
+
```
|
|
36
|
+
### Producer
|
|
37
|
+
The producer component allows you to send messages to Kafka topics.
|
|
38
|
+
|
|
39
|
+
```javascript
|
|
40
|
+
const result = await producer.send({
|
|
41
|
+
topic: 'my-js-topic',
|
|
42
|
+
key: Buffer.from('abc'),
|
|
43
|
+
value: Buffer.from(`{"name":"Elizeu Drummond","phone":"55219123456"}`),
|
|
44
|
+
headers: {key: Buffer.from('value1')},
|
|
45
|
+
});
|
|
46
|
+
console.log('Message sent with offset:', result);
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
### Consumer
|
|
51
|
+
|
|
52
|
+
**Creating a Consumer Instance**
|
|
53
|
+
|
|
54
|
+
Create a consumer instance by specifying the Kafka broker(s), group ID, and other optional configurations:
|
|
55
|
+
|
|
56
|
+
```javascript
|
|
57
|
+
const consumer = kafkaClient.createConsumer({
|
|
58
|
+
topic: 'my-js-topic',
|
|
59
|
+
groupId: 'my-js-group',
|
|
60
|
+
retryStrategy: {
|
|
61
|
+
retries: 3,
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
You can consume messages using the run startConsumer:
|
|
67
|
+
|
|
68
|
+
```javascript
|
|
69
|
+
consumer.startConsumer(async (error, value) => {
|
|
70
|
+
const message = JSON.parse(value.toString());
|
|
71
|
+
const content = await process_my_message(message);
|
|
72
|
+
return ConsumerResult.Ok;
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
## Examples
|
|
76
|
+
|
|
77
|
+
You can find examples of using Kafka Crab JS in the [GitHub repository](https://github.com/inaiat/kafka-crab-js).
|
package/example/sample.mjs
CHANGED
|
@@ -3,14 +3,17 @@ import timersPromises from 'node:timers/promises';
|
|
|
3
3
|
import {Buffer} from 'node:buffer';
|
|
4
4
|
import {ConsumerResult, KafkaClient, KafkaCommitMode, PartitionPosition} from '../index.js';
|
|
5
5
|
|
|
6
|
-
const kafkaClient = new KafkaClient(
|
|
6
|
+
const kafkaClient = new KafkaClient({
|
|
7
|
+
brokers: 'localhost:29092',
|
|
8
|
+
clientId: 'my-id',
|
|
9
|
+
enableAnsiLogger: false});
|
|
7
10
|
const topic = 'my-js-topic';
|
|
8
11
|
|
|
9
12
|
let counter = 0;
|
|
10
13
|
|
|
11
14
|
async function process(message) {
|
|
12
15
|
await timersPromises.setTimeout(1);
|
|
13
|
-
return 'message received: ' + message;
|
|
16
|
+
return 'message received: ' + JSON.stringify(message);
|
|
14
17
|
}
|
|
15
18
|
|
|
16
19
|
const consumer = kafkaClient.createConsumer({
|
|
@@ -27,7 +30,7 @@ console.time('consumer');
|
|
|
27
30
|
|
|
28
31
|
consumer.startConsumer(async (error, value) => {
|
|
29
32
|
if (error) {
|
|
30
|
-
console.error('Consumer error', error);
|
|
33
|
+
console.error('Js Consumer error', error);
|
|
31
34
|
return;
|
|
32
35
|
}
|
|
33
36
|
|
|
@@ -36,19 +39,20 @@ consumer.startConsumer(async (error, value) => {
|
|
|
36
39
|
counter++;
|
|
37
40
|
if (counter >= 0) {
|
|
38
41
|
console.timeEnd('consumer');
|
|
39
|
-
console.log('Counter:', counter, 'Content:', JSON.stringify(content));
|
|
42
|
+
console.log('Js Counter:', counter, 'Content:', JSON.stringify(content));
|
|
40
43
|
console.time('consumer');
|
|
41
44
|
}
|
|
42
45
|
|
|
43
46
|
if (message._id === '3') {
|
|
44
|
-
console.error('Error on process message, let\'s retry',
|
|
47
|
+
console.error('Js Error on process message, let\'s retry', JSON.stringify(content));
|
|
45
48
|
return ConsumerResult.Retry;
|
|
46
49
|
}
|
|
47
50
|
|
|
51
|
+
|
|
48
52
|
return ConsumerResult.Ok;
|
|
49
53
|
});
|
|
50
54
|
|
|
51
|
-
const producer = kafkaClient.createProducer({topic, configuration: {'message.timeout.ms': '
|
|
55
|
+
const producer = kafkaClient.createProducer({topic, configuration: {'message.timeout.ms': '5000'}});
|
|
52
56
|
console.log('Sending message');
|
|
53
57
|
|
|
54
58
|
for (let i = 0; i < 5; i++) {
|
|
@@ -61,9 +65,9 @@ for (let i = 0; i < 5; i++) {
|
|
|
61
65
|
headers: {key: Buffer.from('value1')},
|
|
62
66
|
},
|
|
63
67
|
);
|
|
64
|
-
console.log(result);
|
|
68
|
+
console.log("Js message sent. Offset: ", result);
|
|
65
69
|
await timersPromises.setTimeout(1200);
|
|
66
70
|
} catch (error) {
|
|
67
|
-
console.error('Error on send', error);
|
|
71
|
+
console.error('Js Error on send', error);
|
|
68
72
|
}
|
|
69
73
|
}
|
package/index.d.ts
CHANGED
|
@@ -9,6 +9,13 @@ export const enum SecurityProtocol {
|
|
|
9
9
|
SaslPlaintext = 'SaslPlaintext',
|
|
10
10
|
SaslSsl = 'SaslSsl'
|
|
11
11
|
}
|
|
12
|
+
export interface KafkaConfiguration {
|
|
13
|
+
brokers: string
|
|
14
|
+
clientId: string
|
|
15
|
+
securityProtocol?: SecurityProtocol
|
|
16
|
+
configuration?: Record<string, string>
|
|
17
|
+
enableAnsiLogger?: boolean
|
|
18
|
+
}
|
|
12
19
|
export interface ConsumerConfiguration {
|
|
13
20
|
topic: string
|
|
14
21
|
groupId: string
|
|
@@ -70,20 +77,14 @@ export const enum ConsumerResult {
|
|
|
70
77
|
Ok = 'Ok',
|
|
71
78
|
Retry = 'Retry'
|
|
72
79
|
}
|
|
73
|
-
export class KafkaConfiguration {
|
|
74
|
-
brokers: string
|
|
75
|
-
clientId: string
|
|
76
|
-
securityProtocol?: SecurityProtocol
|
|
77
|
-
configuration?: Record<string, string>
|
|
78
|
-
}
|
|
79
80
|
export class KafkaClient {
|
|
80
81
|
readonly kafkaConfiguration: KafkaConfiguration
|
|
81
|
-
constructor(
|
|
82
|
+
constructor(kafkaConfiguration: KafkaConfiguration)
|
|
82
83
|
createProducer(producerConfiguration: ProducerConfiguration): KafkaProducer
|
|
83
84
|
createConsumer(consumerConfiguration: ConsumerConfiguration): KafkaConsumer
|
|
84
85
|
}
|
|
85
86
|
export class KafkaConsumer {
|
|
86
|
-
startConsumer(callback: (err: Error | null, result: Buffer) => Promise<ConsumerResult>): Promise<void>
|
|
87
|
+
startConsumer(callback: (err: Error | null, result: Buffer) => Promise<ConsumerResult | undefined>): Promise<void>
|
|
87
88
|
}
|
|
88
89
|
export class KafkaProducer {
|
|
89
90
|
send(message: MessageModel): Promise<OwnedDelivery>
|
package/index.js
CHANGED
|
@@ -252,10 +252,9 @@ if (!nativeBinding) {
|
|
|
252
252
|
throw new Error(`Failed to load native binding`)
|
|
253
253
|
}
|
|
254
254
|
|
|
255
|
-
const { SecurityProtocol,
|
|
255
|
+
const { SecurityProtocol, KafkaClient, KafkaConsumer, KafkaProducer, AutoOffsetReset, KafkaCommitMode, PartitionPosition, ConsumerResult } = nativeBinding
|
|
256
256
|
|
|
257
257
|
module.exports.SecurityProtocol = SecurityProtocol
|
|
258
|
-
module.exports.KafkaConfiguration = KafkaConfiguration
|
|
259
258
|
module.exports.KafkaClient = KafkaClient
|
|
260
259
|
module.exports.KafkaConsumer = KafkaConsumer
|
|
261
260
|
module.exports.KafkaProducer = KafkaProducer
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kafka-crab-js",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.10",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"types": "index.d.ts",
|
|
6
6
|
"napi": {
|
|
@@ -15,6 +15,15 @@
|
|
|
15
15
|
}
|
|
16
16
|
},
|
|
17
17
|
"license": "MIT",
|
|
18
|
+
"keywords": [
|
|
19
|
+
"kafka",
|
|
20
|
+
"napi-rs",
|
|
21
|
+
"librdkafka",
|
|
22
|
+
"typescript",
|
|
23
|
+
"rust"
|
|
24
|
+
],
|
|
25
|
+
"author": "inaiat@gmail.com",
|
|
26
|
+
"homepage": "https://github.com/inaiat/kafka-crab-js.git",
|
|
18
27
|
"devDependencies": {
|
|
19
28
|
"@napi-rs/cli": "^2.16.1",
|
|
20
29
|
"ava": "^5.3.1",
|
|
@@ -41,8 +50,8 @@
|
|
|
41
50
|
},
|
|
42
51
|
"packageManager": "yarn@3.6.0",
|
|
43
52
|
"optionalDependencies": {
|
|
44
|
-
"kafka-crab-js-darwin-arm64": "0.0.
|
|
45
|
-
"kafka-crab-js-darwin-x64": "0.0.
|
|
46
|
-
"kafka-crab-js-linux-x64-gnu": "0.0.
|
|
53
|
+
"kafka-crab-js-darwin-arm64": "0.0.10",
|
|
54
|
+
"kafka-crab-js-darwin-x64": "0.0.10",
|
|
55
|
+
"kafka-crab-js-linux-x64-gnu": "0.0.10"
|
|
47
56
|
}
|
|
48
57
|
}
|
|
@@ -55,12 +55,13 @@ impl fmt::Display for SecurityProtocol {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
#[derive(Clone, Debug)]
|
|
58
|
-
#[napi]
|
|
58
|
+
#[napi(object)]
|
|
59
59
|
pub struct KafkaConfiguration {
|
|
60
60
|
pub brokers: String,
|
|
61
61
|
pub client_id: String,
|
|
62
62
|
pub security_protocol: Option<SecurityProtocol>,
|
|
63
63
|
pub configuration: Option<HashMap<String, String>>,
|
|
64
|
+
pub enable_ansi_logger: Option<bool>,
|
|
64
65
|
}
|
|
65
66
|
|
|
66
67
|
#[derive(Clone, Debug)]
|
|
@@ -74,23 +75,18 @@ pub struct KafkaClient {
|
|
|
74
75
|
#[napi]
|
|
75
76
|
impl KafkaClient {
|
|
76
77
|
#[napi(constructor)]
|
|
77
|
-
pub fn new(
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
match tracing_subscriber::fmt::try_init() {
|
|
78
|
+
pub fn new(kafka_configuration: KafkaConfiguration) -> Self {
|
|
79
|
+
match tracing_subscriber::fmt()
|
|
80
|
+
.with_ansi(kafka_configuration.enable_ansi_logger.unwrap_or(false))
|
|
81
|
+
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
|
|
82
|
+
.try_init()
|
|
83
|
+
{
|
|
84
84
|
Ok(_) => {}
|
|
85
|
-
Err(e) =>
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
client_id,
|
|
91
|
-
security_protocol,
|
|
92
|
-
configuration,
|
|
93
|
-
})
|
|
85
|
+
Err(e) => {
|
|
86
|
+
eprintln!("Failed to initialize tracing: {:?}", e);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
KafkaClient::with_kafka_configuration(kafka_configuration)
|
|
94
90
|
}
|
|
95
91
|
|
|
96
92
|
pub fn get_client_config(&self) -> &ClientConfig {
|
|
@@ -103,11 +99,12 @@ impl KafkaClient {
|
|
|
103
99
|
security_protocol,
|
|
104
100
|
client_id,
|
|
105
101
|
configuration,
|
|
102
|
+
..
|
|
106
103
|
} = kafka_configuration.clone();
|
|
107
104
|
|
|
108
105
|
let mut rdkafka_client_config = ClientConfig::new();
|
|
109
106
|
|
|
110
|
-
rdkafka_client_config.set_log_level(RDKafkaLogLevel::
|
|
107
|
+
rdkafka_client_config.set_log_level(RDKafkaLogLevel::Debug);
|
|
111
108
|
rdkafka_client_config.set("bootstrap.servers", brokers);
|
|
112
109
|
rdkafka_client_config.set("client.id", client_id);
|
|
113
110
|
if let Some(security_protocol) = security_protocol {
|
|
@@ -92,7 +92,9 @@ impl KafkaConsumer {
|
|
|
92
92
|
})
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
#[napi(
|
|
95
|
+
#[napi(
|
|
96
|
+
ts_args_type = "callback: (err: Error | null, result: Buffer) => Promise<ConsumerResult | undefined>"
|
|
97
|
+
)]
|
|
96
98
|
pub async fn start_consumer(&self, func: ThreadsafeFunction<Buffer>) -> Result<()> {
|
|
97
99
|
let ConsumerConfiguration {
|
|
98
100
|
commit_mode,
|
|
@@ -304,22 +306,22 @@ async fn process_message(
|
|
|
304
306
|
match message.payload_view::<[u8]>() {
|
|
305
307
|
None => Ok(None),
|
|
306
308
|
Some(Ok(payload)) => match func
|
|
307
|
-
.call_async::<Promise<ConsumerResult
|
|
309
|
+
.call_async::<Promise<Option<ConsumerResult>>>(Ok(payload.into()))
|
|
308
310
|
.await
|
|
309
311
|
{
|
|
310
312
|
Ok(js_result) => match js_result.await {
|
|
311
313
|
Ok(value) => match value {
|
|
312
|
-
ConsumerResult::Ok => {
|
|
314
|
+
None | Some(ConsumerResult::Ok) => {
|
|
313
315
|
if let Some(commit_mode) = commit_mode {
|
|
314
316
|
match stream_consumer.commit_message(message, *commit_mode) {
|
|
315
|
-
Ok(_) => Ok(Some(
|
|
317
|
+
Ok(_) => Ok(Some(ConsumerResult::Ok)),
|
|
316
318
|
Err(e) => Err(anyhow::Error::new(e)),
|
|
317
319
|
}
|
|
318
320
|
} else {
|
|
319
|
-
Ok(Some(
|
|
321
|
+
Ok(Some(ConsumerResult::Ok))
|
|
320
322
|
}
|
|
321
323
|
}
|
|
322
|
-
ConsumerResult::Retry => Ok(Some(
|
|
324
|
+
Some(ConsumerResult::Retry) => Ok(Some(ConsumerResult::Retry)),
|
|
323
325
|
},
|
|
324
326
|
Err(e) => Err(anyhow::Error::new(e)),
|
|
325
327
|
},
|