@venizia/ignis-docs 0.0.7-1 → 0.0.7-2
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 +1 -1
- package/wiki/references/helpers/kafka/admin.md +173 -0
- package/wiki/references/helpers/kafka/consumer.md +473 -0
- package/wiki/references/helpers/kafka/examples.md +234 -0
- package/wiki/references/helpers/kafka/index.md +397 -220
- package/wiki/references/helpers/kafka/producer.md +269 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# Examples & Troubleshooting
|
|
2
|
+
|
|
3
|
+
Complete examples and common issue resolution for the Kafka helpers.
|
|
4
|
+
|
|
5
|
+
## Producer: Interval-Based Message Sending
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { Producer, serializersFrom, jsonSerializer, stringSerializer } from '@platformatic/kafka';
|
|
9
|
+
|
|
10
|
+
const producer = new Producer({
|
|
11
|
+
clientId: 'interval-producer',
|
|
12
|
+
bootstrapBrokers: ['broker1:9092', 'broker2:9092', 'broker3:9092'],
|
|
13
|
+
serializers: { ...serializersFrom(jsonSerializer), key: stringSerializer },
|
|
14
|
+
sasl: { mechanism: 'SCRAM-SHA-512', username: 'user', password: 'pass' },
|
|
15
|
+
connectTimeout: 30_000,
|
|
16
|
+
requestTimeout: 30_000,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
let count = 0;
|
|
20
|
+
const interval = setInterval(async () => {
|
|
21
|
+
const key = `key-${count % 3}`;
|
|
22
|
+
const value = { index: count, timestamp: new Date().toISOString() };
|
|
23
|
+
|
|
24
|
+
await producer.send({ messages: [{ topic: 'events', key, value }] });
|
|
25
|
+
console.log(JSON.stringify({ topic: 'events', key, value }));
|
|
26
|
+
count++;
|
|
27
|
+
}, 100);
|
|
28
|
+
|
|
29
|
+
process.on('SIGINT', async () => {
|
|
30
|
+
clearInterval(interval);
|
|
31
|
+
console.log(`Shutting down... (sent ${count} messages)`);
|
|
32
|
+
await producer.close();
|
|
33
|
+
process.exit(0);
|
|
34
|
+
});
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Consumer: Event-Based with Manual Commit
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
import { Consumer, deserializersFrom, jsonDeserializer, stringDeserializer } from '@platformatic/kafka';
|
|
41
|
+
|
|
42
|
+
const consumer = new Consumer({
|
|
43
|
+
clientId: 'event-consumer',
|
|
44
|
+
bootstrapBrokers: ['broker1:9092', 'broker2:9092', 'broker3:9092'],
|
|
45
|
+
groupId: 'processing-group',
|
|
46
|
+
deserializers: { ...deserializersFrom(jsonDeserializer), key: stringDeserializer },
|
|
47
|
+
sasl: { mechanism: 'SCRAM-SHA-512', username: 'user', password: 'pass' },
|
|
48
|
+
connectTimeout: 30_000,
|
|
49
|
+
requestTimeout: 30_000,
|
|
50
|
+
autocommit: false,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const stream = await consumer.consume({
|
|
54
|
+
topics: ['events'],
|
|
55
|
+
mode: 'committed',
|
|
56
|
+
fallbackMode: 'latest',
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
stream.on('data', (message) => {
|
|
60
|
+
console.log(JSON.stringify({
|
|
61
|
+
topic: message.topic,
|
|
62
|
+
partition: message.partition,
|
|
63
|
+
offset: message.offset,
|
|
64
|
+
key: message.key,
|
|
65
|
+
value: message.value,
|
|
66
|
+
headers: Object.fromEntries(message.headers ?? new Map()),
|
|
67
|
+
timestamp: message.timestamp,
|
|
68
|
+
}, (_key, value) => (typeof value === 'bigint' ? value.toString() : value)));
|
|
69
|
+
|
|
70
|
+
message.commit();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
stream.on('error', (err) => console.error('Stream error:', err));
|
|
74
|
+
|
|
75
|
+
process.on('SIGINT', async () => {
|
|
76
|
+
await stream.close();
|
|
77
|
+
await consumer.close();
|
|
78
|
+
process.exit(0);
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Admin: Topic Setup Script
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
import { KafkaAdminHelper } from '@venizia/ignis-helpers/kafka';
|
|
86
|
+
|
|
87
|
+
async function setupTopics() {
|
|
88
|
+
const helper = KafkaAdminHelper.newInstance({
|
|
89
|
+
bootstrapBrokers: ['localhost:9092'],
|
|
90
|
+
clientId: 'topic-setup',
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const admin = helper.getAdmin();
|
|
94
|
+
|
|
95
|
+
// Create topics
|
|
96
|
+
await admin.createTopics({
|
|
97
|
+
topics: ['orders', 'inventory', 'notifications'],
|
|
98
|
+
partitions: 6,
|
|
99
|
+
replicas: 3,
|
|
100
|
+
configs: [
|
|
101
|
+
{ name: 'retention.ms', value: '604800000' },
|
|
102
|
+
{ name: 'compression.type', value: 'zstd' },
|
|
103
|
+
],
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// Verify
|
|
107
|
+
const topics = await admin.listTopics({ includeInternals: false });
|
|
108
|
+
console.log('Topics:', topics);
|
|
109
|
+
|
|
110
|
+
await helper.close();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
setupTopics();
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Using Helpers with Ignis IoC
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
import { KafkaProducerHelper, KafkaConsumerHelper } from '@venizia/ignis-helpers/kafka';
|
|
120
|
+
import { stringSerializers, stringDeserializers } from '@platformatic/kafka';
|
|
121
|
+
import { inject, injectable } from '@venizia/ignis-inversion';
|
|
122
|
+
|
|
123
|
+
@injectable()
|
|
124
|
+
export class OrderEventService {
|
|
125
|
+
private producer: KafkaProducerHelper;
|
|
126
|
+
private consumer: KafkaConsumerHelper;
|
|
127
|
+
|
|
128
|
+
constructor(
|
|
129
|
+
@inject({ key: 'kafka.producer' }) producer: KafkaProducerHelper,
|
|
130
|
+
@inject({ key: 'kafka.consumer' }) consumer: KafkaConsumerHelper,
|
|
131
|
+
) {
|
|
132
|
+
this.producer = producer;
|
|
133
|
+
this.consumer = consumer;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async publishOrderCreated(orderId: string, data: Record<string, unknown>) {
|
|
137
|
+
const producer = this.producer.getProducer();
|
|
138
|
+
await producer.send({
|
|
139
|
+
messages: [{ topic: 'order-events', key: orderId, value: JSON.stringify(data) }],
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async startConsuming() {
|
|
144
|
+
const consumer = this.consumer.getConsumer();
|
|
145
|
+
const stream = await consumer.consume({
|
|
146
|
+
topics: ['order-events'],
|
|
147
|
+
mode: 'committed',
|
|
148
|
+
fallbackMode: 'latest',
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
for await (const message of stream) {
|
|
152
|
+
await this.handleOrderEvent(message.key!, JSON.parse(message.value!));
|
|
153
|
+
await message.commit();
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
private async handleOrderEvent(orderId: string, data: Record<string, unknown>) {
|
|
158
|
+
// Process order event
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Register in application
|
|
163
|
+
app.bind('kafka.producer').to(
|
|
164
|
+
KafkaProducerHelper.newInstance({
|
|
165
|
+
bootstrapBrokers: ['localhost:9092'],
|
|
166
|
+
clientId: 'order-service-producer',
|
|
167
|
+
serializers: stringSerializers,
|
|
168
|
+
}),
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
app.bind('kafka.consumer').to(
|
|
172
|
+
KafkaConsumerHelper.newInstance({
|
|
173
|
+
bootstrapBrokers: ['localhost:9092'],
|
|
174
|
+
clientId: 'order-service-consumer',
|
|
175
|
+
groupId: 'order-service',
|
|
176
|
+
deserializers: stringDeserializers,
|
|
177
|
+
}),
|
|
178
|
+
);
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Troubleshooting
|
|
184
|
+
|
|
185
|
+
### Common Issues
|
|
186
|
+
|
|
187
|
+
| Error | Cause | Fix |
|
|
188
|
+
|-------|-------|-----|
|
|
189
|
+
| `ECONNREFUSED localhost:9092` | Broker `advertised.listeners` set to `localhost` but connecting remotely | Set `KAFKA_ADVERTISED_LISTENERS` with the correct external host IP |
|
|
190
|
+
| `Request timed out` | SASL handshake or broker unreachable | Add `connectTimeout: 30_000, requestTimeout: 30_000` |
|
|
191
|
+
| `Connection closed` | Connecting without SASL to a SASL-required listener | Check `KAFKA_LISTENER_SECURITY_PROTOCOL_MAP` — use `SASL_PLAINTEXT` |
|
|
192
|
+
| `Cannot find a suitable SASL mechanism` | Wrong mechanism (e.g., `PLAIN` when broker only supports `SCRAM-SHA-512`) | Check error message for supported mechanisms, match `mechanism` |
|
|
193
|
+
| `Failed to deserialize a message` | Mismatch between serializer used for producing and deserializer used for consuming | Ensure matching serde. For old data, use a new consumer group or recreate topic |
|
|
194
|
+
| `JSON.stringify cannot serialize BigInt` | `message.offset` and `message.timestamp` are `bigint` | Use custom replacer: `(_k, v) => typeof v === 'bigint' ? v.toString() : v` |
|
|
195
|
+
| Consumer idle (no messages) | More consumers than partitions | Ensure `numPartitions >= numConsumers` |
|
|
196
|
+
|
|
197
|
+
### Docker Kafka Configuration
|
|
198
|
+
|
|
199
|
+
When running Kafka in Docker and connecting from outside the container:
|
|
200
|
+
|
|
201
|
+
```yaml
|
|
202
|
+
environment:
|
|
203
|
+
DOCKER_HOST_IP: '192.168.1.100' # Your host machine's IP
|
|
204
|
+
KAFKA_ADVERTISED_LISTENERS: >
|
|
205
|
+
INTERNAL://kafka-1:29092,
|
|
206
|
+
EXTERNAL://${DOCKER_HOST_IP}:19092
|
|
207
|
+
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: >
|
|
208
|
+
INTERNAL:PLAINTEXT,
|
|
209
|
+
EXTERNAL:SASL_PLAINTEXT,
|
|
210
|
+
CONTROLLER:PLAINTEXT
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
- `INTERNAL` — used for inter-broker communication
|
|
214
|
+
- `EXTERNAL` — used for client connections from outside Docker
|
|
215
|
+
- `CONTROLLER` — used for KRaft controller communication
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## See Also
|
|
220
|
+
|
|
221
|
+
- **Kafka Pages:**
|
|
222
|
+
- [Overview & Fundamentals](./) — Connection, serialization, constants, compression
|
|
223
|
+
- [Producer](./producer) — Producer helper & API reference
|
|
224
|
+
- [Consumer](./consumer) — Consumer helper & API reference
|
|
225
|
+
- [Admin](./admin) — Admin helper & API reference
|
|
226
|
+
|
|
227
|
+
- **Other Helpers:**
|
|
228
|
+
- [Queue Helper](../queue/) — BullMQ, MQTT, and in-memory queues
|
|
229
|
+
- [Redis Helper](../redis/) — Redis connection management
|
|
230
|
+
|
|
231
|
+
- **External Resources:**
|
|
232
|
+
- [@platformatic/kafka](https://github.com/platformatic/kafka) — Underlying Kafka client library
|
|
233
|
+
- [Apache Kafka Documentation](https://kafka.apache.org/documentation/) — Official Kafka docs
|
|
234
|
+
- [KIP-848](https://cwiki.apache.org/confluence/display/KAFKA/KIP-848) — New consumer group protocol
|