@venizia/ignis-docs 0.2.0 → 0.2.1-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.
- package/README.md +14 -14
- package/content/best-practices/api-usage-examples.md +39 -19
- package/content/best-practices/architectural-patterns.md +24 -13
- package/content/best-practices/architecture-decisions.md +29 -16
- package/content/best-practices/code-style-standards/advanced-patterns.md +43 -31
- package/content/best-practices/code-style-standards/constants-configuration.md +19 -4
- package/content/best-practices/code-style-standards/control-flow.md +33 -1
- package/content/best-practices/code-style-standards/documentation.md +28 -8
- package/content/best-practices/code-style-standards/function-patterns.md +15 -4
- package/content/best-practices/code-style-standards/index.md +7 -2
- package/content/best-practices/code-style-standards/naming-conventions.md +27 -3
- package/content/best-practices/code-style-standards/route-definitions.md +9 -5
- package/content/best-practices/code-style-standards/tooling.md +14 -1
- package/content/best-practices/code-style-standards/type-safety.md +39 -6
- package/content/best-practices/common-pitfalls.md +59 -35
- package/content/best-practices/contribution-workflow.md +8 -4
- package/content/best-practices/data-modeling.md +78 -62
- package/content/best-practices/deployment-strategies.md +56 -19
- package/content/best-practices/error-handling.md +247 -153
- package/content/best-practices/index.md +6 -0
- package/content/best-practices/performance-optimization.md +26 -13
- package/content/best-practices/security-guidelines.md +35 -9
- package/content/best-practices/testing-strategies.md +7 -2
- package/content/best-practices/troubleshooting-tips.md +27 -17
- package/content/extensions/components/api-reference.md +109 -323
- package/content/extensions/components/authentication/api.md +489 -602
- package/content/extensions/components/authentication/errors.md +135 -498
- package/content/extensions/components/authentication/index.md +89 -801
- package/content/extensions/components/authentication/usage.md +231 -955
- package/content/extensions/components/authorization/api.md +991 -644
- package/content/extensions/components/authorization/errors.md +204 -208
- package/content/extensions/components/authorization/getting-started.md +227 -0
- package/content/extensions/components/authorization/index.md +88 -795
- package/content/extensions/components/authorization/usage.md +219 -528
- package/content/extensions/components/health-check.md +77 -243
- package/content/extensions/components/index.md +24 -90
- package/content/extensions/components/mail/api.md +553 -285
- package/content/extensions/components/mail/errors.md +76 -62
- package/content/extensions/components/mail/index.md +111 -463
- package/content/extensions/components/mail/usage.md +139 -173
- package/content/extensions/components/request-tracker.md +70 -173
- package/content/extensions/components/socket-io/api.md +462 -785
- package/content/extensions/components/socket-io/errors.md +49 -51
- package/content/extensions/components/socket-io/index.md +69 -372
- package/content/extensions/components/socket-io/usage.md +212 -105
- package/content/extensions/components/static-asset/api.md +461 -141
- package/content/extensions/components/static-asset/errors.md +121 -53
- package/content/extensions/components/static-asset/index.md +84 -606
- package/content/extensions/components/static-asset/usage.md +184 -299
- package/content/extensions/components/template/index.md +3 -3
- package/content/extensions/components/websocket/api.md +311 -404
- package/content/extensions/components/websocket/errors.md +47 -56
- package/content/extensions/components/websocket/index.md +75 -407
- package/content/extensions/components/websocket/usage.md +120 -338
- package/content/extensions/helpers/cron/index.md +52 -160
- package/content/extensions/helpers/crypto/index.md +67 -480
- package/content/extensions/helpers/crypto/reference.md +528 -0
- package/content/extensions/helpers/env/index.md +64 -178
- package/content/extensions/helpers/error/index.md +286 -196
- package/content/extensions/helpers/index.md +61 -47
- package/content/extensions/helpers/inversion/index.md +76 -550
- package/content/extensions/helpers/inversion/reference.md +530 -0
- package/content/extensions/helpers/kafka/admin.md +23 -3
- package/content/extensions/helpers/kafka/compile-binary.md +83 -52
- package/content/extensions/helpers/kafka/consumer.md +65 -28
- package/content/extensions/helpers/kafka/examples.md +46 -253
- package/content/extensions/helpers/kafka/index.md +55 -617
- package/content/extensions/helpers/kafka/producer.md +156 -22
- package/content/extensions/helpers/kafka/schema-registry.md +59 -79
- package/content/extensions/helpers/logger/hf-logger.md +220 -0
- package/content/extensions/helpers/logger/index.md +78 -552
- package/content/extensions/helpers/logger/pino.md +105 -0
- package/content/extensions/helpers/logger/reference.md +937 -0
- package/content/extensions/helpers/network/api.md +276 -195
- package/content/extensions/helpers/network/index.md +87 -524
- package/content/extensions/helpers/queue/index.md +80 -897
- package/content/extensions/helpers/queue/reference.md +494 -0
- package/content/extensions/helpers/redis/index.md +86 -640
- package/content/extensions/helpers/redis/reference.md +784 -0
- package/content/extensions/helpers/secrets/index.md +136 -0
- package/content/extensions/helpers/socket-io/api.md +325 -204
- package/content/extensions/helpers/socket-io/index.md +79 -429
- package/content/extensions/helpers/storage/api.md +584 -464
- package/content/extensions/helpers/storage/index.md +80 -573
- package/content/extensions/helpers/types/index.md +75 -495
- package/content/extensions/helpers/types/reference.md +689 -0
- package/content/extensions/helpers/uid/index.md +176 -189
- package/content/extensions/helpers/websocket/api.md +366 -214
- package/content/extensions/helpers/websocket/index.md +68 -503
- package/content/extensions/helpers/worker-thread/index.md +62 -396
- package/content/extensions/helpers/worker-thread/reference.md +428 -0
- package/content/extensions/index.md +38 -39
- package/content/extensions/src-details/mcp-server.md +96 -548
- package/content/guides/core-concepts/persistent/datasources.md +2 -2
- package/content/guides/core-concepts/persistent/index.md +5 -1
- package/content/guides/core-concepts/persistent/models.md +1 -1
- package/content/guides/core-concepts/persistent/pglite.md +218 -0
- package/content/guides/core-concepts/persistent/postgres-drivers.md +21 -15
- package/content/guides/core-concepts/persistent/search-meilisearch.md +22 -12
- package/content/guides/core-concepts/persistent/search-typesense.md +28 -16
- package/content/guides/core-concepts/persistent/sqlite.md +296 -0
- package/content/guides/core-concepts/persistent/transactions.md +12 -11
- package/content/guides/core-concepts/secrets-vault.md +177 -0
- package/content/guides/core-concepts/services.md +1 -1
- package/content/guides/get-started/5-minute-quickstart.md +59 -206
- package/content/guides/get-started/philosophy.md +135 -670
- package/content/guides/get-started/setup.md +53 -74
- package/content/guides/migrations/redis-helpers-migration.md +5 -4
- package/content/guides/migrations/scoped-rbac-migration.md +5 -5
- package/content/guides/migrations/unified-connectors-migration.md +8 -7
- package/content/guides/tutorials/ecommerce-api.md +3 -8
- package/content/guides/tutorials/realtime-chat.md +1 -1
- package/content/references/base/application.md +64 -22
- package/content/references/base/components.md +3 -3
- package/content/references/base/connectors.md +79 -136
- package/content/references/base/controllers.md +12 -12
- package/content/references/base/datasources-reference.md +600 -0
- package/content/references/base/datasources.md +84 -444
- package/content/references/base/dependency-injection.md +25 -46
- package/content/references/base/filter-system/application-usage.md +95 -123
- package/content/references/base/filter-system/array-operators.md +33 -43
- package/content/references/base/filter-system/comparison-operators.md +55 -63
- package/content/references/base/filter-system/default-filter.md +144 -350
- package/content/references/base/filter-system/fields-order-pagination.md +116 -148
- package/content/references/base/filter-system/index.md +114 -253
- package/content/references/base/filter-system/json-filtering.md +52 -181
- package/content/references/base/filter-system/list-operators.md +28 -44
- package/content/references/base/filter-system/logical-operators.md +69 -114
- package/content/references/base/filter-system/null-operators.md +41 -98
- package/content/references/base/filter-system/pattern-matching.md +48 -51
- package/content/references/base/filter-system/quick-reference.md +93 -196
- package/content/references/base/filter-system/range-operators.md +22 -38
- package/content/references/base/filter-system/tips.md +70 -133
- package/content/references/base/filter-system/use-cases.md +173 -232
- package/content/references/base/grpc-controllers.md +53 -17
- package/content/references/base/index.md +5 -3
- package/content/references/base/middlewares.md +43 -28
- package/content/references/base/models-reference.md +886 -0
- package/content/references/base/models.md +81 -1452
- package/content/references/base/providers.md +8 -8
- package/content/references/base/repositories/advanced.md +281 -419
- package/content/references/base/repositories/index.md +84 -644
- package/content/references/base/repositories/mixins.md +25 -21
- package/content/references/base/repositories/relations.md +194 -375
- package/content/references/base/repositories/soft-deletable.md +67 -55
- package/content/references/base/secrets.md +267 -0
- package/content/references/base/services.md +8 -6
- package/content/references/configuration/environment-variables.md +73 -21
- package/content/references/configuration/index.md +51 -31
- package/content/references/index.md +1 -1
- package/content/references/quick-reference.md +3 -16
- package/content/references/utilities/crypto.md +35 -76
- package/content/references/utilities/date.md +33 -73
- package/content/references/utilities/duration.md +85 -0
- package/content/references/utilities/index.md +6 -2
- package/content/references/utilities/jsx-reference.md +298 -0
- package/content/references/utilities/jsx.md +82 -525
- package/content/references/utilities/module.md +81 -61
- package/content/references/utilities/parse.md +34 -64
- package/content/references/utilities/performance.md +33 -58
- package/content/references/utilities/promise.md +28 -62
- package/content/references/utilities/request.md +58 -218
- package/content/references/utilities/retry.md +139 -0
- package/content/references/utilities/schema.md +43 -137
- package/content/references/utilities/statuses-reference.md +361 -0
- package/content/references/utilities/statuses.md +63 -667
- package/dist/mcp-server/index.js +0 -0
- package/dist/mcp-server/tools/github/list-project-files.tool.d.ts +1 -1
- package/dist/mcp-server/tools/github/list-project-files.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/github/list-project-files.tool.js +3 -3
- package/dist/mcp-server/tools/github/search-code.tool.js +1 -1
- package/dist/mcp-server/tools/github/verify-dependencies.tool.js +1 -1
- package/dist/mcp-server/tools/github/view-source-file.tool.js +1 -1
- package/package.json +24 -23
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Kafka Producer
|
|
3
|
+
description: KafkaProducerHelper - connection, SASL, serialization, compression, and transactions
|
|
4
|
+
difficulty: intermediate
|
|
5
|
+
---
|
|
6
|
+
|
|
1
7
|
# Producer
|
|
2
8
|
|
|
3
9
|
The `KafkaProducerHelper` wraps `@platformatic/kafka`'s `Producer` with health tracking, graceful shutdown, broker event callbacks, and a transaction helper.
|
|
@@ -34,19 +40,61 @@ interface IKafkaProducerOptions<KeyType, ValueType, HeaderKeyType, HeaderValueTy
|
|
|
34
40
|
| Option | Type | Default | Description |
|
|
35
41
|
|--------|------|---------|-------------|
|
|
36
42
|
| `identifier` | `string` | `'kafka-producer'` | Scoped logging identifier |
|
|
37
|
-
| `serializers` | `Partial<Serializers<K,V,HK,HV>>` |
|
|
38
|
-
| `compression` | `CompressionAlgorithmValue` |
|
|
39
|
-
| `acks` | `TKafkaAcks` |
|
|
40
|
-
| `idempotent` | `boolean` |
|
|
41
|
-
| `transactionalId` | `string` |
|
|
42
|
-
| `strict` | `boolean` | `true` | Strict mode
|
|
43
|
+
| `serializers` | `Partial<Serializers<K,V,HK,HV>>` | - | Key/value/header serializers |
|
|
44
|
+
| `compression` | `CompressionAlgorithmValue` | - | `'none'`, `'gzip'`, `'snappy'`, `'lz4'`, `'zstd'` |
|
|
45
|
+
| `acks` | `TKafkaAcks` | - | Acknowledgment level: `0` (none), `1` (leader), `-1` (all) |
|
|
46
|
+
| `idempotent` | `boolean` | - | Enable idempotent producer (exactly-once within partition) |
|
|
47
|
+
| `transactionalId` | `string` | - | Transactional ID for exactly-once across partitions |
|
|
48
|
+
| `strict` | `boolean` | `true` | Strict mode - fail on unknown topics |
|
|
43
49
|
| `autocreateTopics` | `boolean` | `false` | Auto-create topics on first produce |
|
|
44
50
|
| `shutdownTimeout` | `number` | `30000` | Graceful shutdown timeout in ms |
|
|
45
|
-
| `registry` | `SchemaRegistry` |
|
|
46
|
-
| `onBrokerConnect` | `TKafkaBrokerEventCallback` |
|
|
47
|
-
| `onBrokerDisconnect` | `TKafkaBrokerEventCallback` |
|
|
51
|
+
| `registry` | `SchemaRegistry` | - | Schema registry for auto ser/deser |
|
|
52
|
+
| `onBrokerConnect` | `TKafkaBrokerEventCallback` | - | Called when broker connects |
|
|
53
|
+
| `onBrokerDisconnect` | `TKafkaBrokerEventCallback` | - | Called when broker disconnects |
|
|
54
|
+
|
|
55
|
+
Plus the shared [Connection & Authentication](#connection--authentication) options below, all inherited from `IKafkaConnectionOptions`.
|
|
56
|
+
|
|
57
|
+
## Connection & Authentication
|
|
58
|
+
|
|
59
|
+
`IKafkaProducerOptions`, `IKafkaConsumerOptions`, and `IKafkaAdminOptions` all extend `IKafkaConnectionOptions` - this section applies to all three.
|
|
60
|
+
|
|
61
|
+
| Option | Type | Default | Description |
|
|
62
|
+
|--------|------|---------|-------------|
|
|
63
|
+
| `bootstrapBrokers` | `string[]` | - | Broker addresses (`host:port`). **Required** |
|
|
64
|
+
| `clientId` | `string` | - | Unique client identifier. **Required** |
|
|
65
|
+
| `retries` | `number` | `3` | Connection retries before failing |
|
|
66
|
+
| `retryDelay` | `number` | `1000` | Delay between retries (ms) |
|
|
67
|
+
| `sasl` | `SASLOptions` | - | SASL authentication |
|
|
68
|
+
| `tls` / `ssl` | `TLSConnectionOptions` | - | TLS options (`ssl` is an alias for `tls`) |
|
|
69
|
+
| `connectTimeout` | `number` | - | TCP connection timeout (ms) |
|
|
70
|
+
| `requestTimeout` | `number` | - | Kafka request timeout (ms) |
|
|
71
|
+
|
|
72
|
+
**SASL mechanisms** (`@platformatic/kafka` supports five):
|
|
73
|
+
|
|
74
|
+
| Mechanism | Use case |
|
|
75
|
+
|-----------|----------|
|
|
76
|
+
| `PLAIN` | Username/password (pair with `tls` in production) |
|
|
77
|
+
| `SCRAM-SHA-256` / `SCRAM-SHA-512` | Challenge-response - password never sent in plaintext |
|
|
78
|
+
| `OAUTHBEARER` | Token-based - Azure Event Hubs, Confluent Cloud. `token` accepts a string or an async function that returns one |
|
|
79
|
+
| `GSSAPI` | Kerberos authentication |
|
|
48
80
|
|
|
49
|
-
|
|
81
|
+
```typescript
|
|
82
|
+
import fs from 'node:fs';
|
|
83
|
+
import { KafkaProducerHelper } from '@venizia/ignis-helpers/kafka';
|
|
84
|
+
|
|
85
|
+
const producer = KafkaProducerHelper.newInstance({
|
|
86
|
+
bootstrapBrokers: ['broker1:9093', 'broker2:9093'],
|
|
87
|
+
clientId: 'order-producer',
|
|
88
|
+
sasl: { mechanism: 'SCRAM-SHA-512', username: 'kafka-user', password: 'kafka-password' },
|
|
89
|
+
tls: {
|
|
90
|
+
ca: fs.readFileSync('/path/to/ca.pem'),
|
|
91
|
+
cert: fs.readFileSync('/path/to/client-cert.pem'),
|
|
92
|
+
key: fs.readFileSync('/path/to/client-key.pem'),
|
|
93
|
+
},
|
|
94
|
+
connectTimeout: 30_000,
|
|
95
|
+
requestTimeout: 30_000,
|
|
96
|
+
});
|
|
97
|
+
```
|
|
50
98
|
|
|
51
99
|
## Basic Example
|
|
52
100
|
|
|
@@ -92,6 +140,74 @@ await helper.close();
|
|
|
92
140
|
await helper.close({ isForce: true });
|
|
93
141
|
```
|
|
94
142
|
|
|
143
|
+
## Serialization
|
|
144
|
+
|
|
145
|
+
`@platformatic/kafka`'s default wire format is `Buffer`. The helpers default the generic types to `string`, but that's a type default only. Pass serializers explicitly, or messages travel as raw `Buffer`.
|
|
146
|
+
|
|
147
|
+
| Export | Type | Description |
|
|
148
|
+
|--------|------|-------------|
|
|
149
|
+
| `stringSerializer` / `stringDeserializer` | `Serializer<string>` / `Deserializer<string>` | UTF-8 string <-> `Buffer` |
|
|
150
|
+
| `jsonSerializer` / `jsonDeserializer` | `Serializer<T>` / `Deserializer<T>` | `JSON.stringify` / `JSON.parse` + UTF-8 |
|
|
151
|
+
| `stringSerializers` / `stringDeserializers` | `Serializers<string,string,string,string>` / `Deserializers<...>` | All four positions (key, value, header key, header value) as string |
|
|
152
|
+
| `serializersFrom(s)` / `deserializersFrom(d)` | `<T>(fn) => Serializers<T,T,T,T>` / `<T>(fn) => Deserializers<T,T,T,T>` | Build all four positions from a single serializer/deserializer |
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
import { stringSerializers } from '@platformatic/kafka';
|
|
156
|
+
|
|
157
|
+
const producer = KafkaProducerHelper.newInstance({
|
|
158
|
+
bootstrapBrokers: ['localhost:9092'],
|
|
159
|
+
clientId: 'my-producer',
|
|
160
|
+
serializers: stringSerializers,
|
|
161
|
+
});
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
import { jsonSerializer, stringSerializer, serializersFrom } from '@platformatic/kafka';
|
|
166
|
+
|
|
167
|
+
const producer = KafkaProducerHelper.newInstance({
|
|
168
|
+
bootstrapBrokers: ['localhost:9092'],
|
|
169
|
+
clientId: 'my-producer',
|
|
170
|
+
serializers: { ...serializersFrom(jsonSerializer), key: stringSerializer },
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
await producer.getProducer().send({
|
|
174
|
+
messages: [{
|
|
175
|
+
topic: 'orders',
|
|
176
|
+
key: 'order-123',
|
|
177
|
+
value: { id: '123', status: 'created', amount: 99 },
|
|
178
|
+
}],
|
|
179
|
+
});
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
For schema-validated serialization (Avro, Protobuf, JSON Schema), pass a `registry` instead of `serializers` - see [Schema Registry](./schema-registry).
|
|
183
|
+
|
|
184
|
+
## Compression
|
|
185
|
+
|
|
186
|
+
`@platformatic/kafka` supports five compression algorithms:
|
|
187
|
+
|
|
188
|
+
| Algorithm | Value | Description |
|
|
189
|
+
|-----------|-------|-------------|
|
|
190
|
+
| None | `'none'` | No compression (default) |
|
|
191
|
+
| GZIP | `'gzip'` | Good compression ratio, moderate CPU |
|
|
192
|
+
| Snappy | `'snappy'` | Fast compression, moderate ratio |
|
|
193
|
+
| LZ4 | `'lz4'` | Very fast, good for high-throughput |
|
|
194
|
+
| Zstandard | `'zstd'` | Best ratio, moderate CPU |
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
const helper = KafkaProducerHelper.newInstance({
|
|
198
|
+
bootstrapBrokers: ['localhost:9092'],
|
|
199
|
+
clientId: 'my-producer',
|
|
200
|
+
serializers: stringSerializers,
|
|
201
|
+
compression: 'zstd',
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
// Override per-send
|
|
205
|
+
await helper.getProducer().send({
|
|
206
|
+
messages: [{ topic: 'logs', key: 'l1', value: largePayload }],
|
|
207
|
+
compression: 'lz4',
|
|
208
|
+
});
|
|
209
|
+
```
|
|
210
|
+
|
|
95
211
|
## Transactions
|
|
96
212
|
|
|
97
213
|
`runInTransaction()` wraps `beginTransaction()` -> callback -> `commit()` / `abort()` with automatic logging.
|
|
@@ -133,6 +249,8 @@ const result = await helper.runInTransaction(async ({ send, addConsumer, addOffs
|
|
|
133
249
|
});
|
|
134
250
|
```
|
|
135
251
|
|
|
252
|
+
If the callback throws, the transaction is automatically aborted and the error re-thrown.
|
|
253
|
+
|
|
136
254
|
### Transaction Context
|
|
137
255
|
|
|
138
256
|
The callback receives an `IKafkaTransactionContext`:
|
|
@@ -144,17 +262,17 @@ The callback receives an `IKafkaTransactionContext`:
|
|
|
144
262
|
| `addConsumer(consumer)` | `(consumer: Consumer) => Promise<void>` | Add a consumer for exactly-once |
|
|
145
263
|
| `addOffset(message)` | `(message: Message) => Promise<void>` | Add consumed message offset to transaction |
|
|
146
264
|
|
|
147
|
-
If the callback throws, the transaction is automatically aborted and the error re-thrown.
|
|
148
|
-
|
|
149
265
|
## Graceful Shutdown
|
|
150
266
|
|
|
151
|
-
`close()`
|
|
267
|
+
`close()` runs a two-phase shutdown:
|
|
152
268
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
269
|
+
| Phase | When it runs | What happens |
|
|
270
|
+
|---|---|---|
|
|
271
|
+
| Graceful | Default | Calls `close(true)` on the underlying producer, capped at `shutdownTimeout` (default 30s) |
|
|
272
|
+
| Force fallback | Graceful times out | Force-closes automatically, no further waiting |
|
|
273
|
+
| Force | `close({ isForce: true })` | Calls `close(true)` immediately, no timeout |
|
|
156
274
|
|
|
157
|
-
After `close()`, all broker tracking is cleared and `healthStatus`
|
|
275
|
+
After `close()`, all broker tracking is cleared and `healthStatus` becomes `'disconnected'`.
|
|
158
276
|
|
|
159
277
|
```typescript
|
|
160
278
|
// Graceful (recommended)
|
|
@@ -166,7 +284,7 @@ await helper.close({ isForce: true });
|
|
|
166
284
|
|
|
167
285
|
## API Reference (`@platformatic/kafka`)
|
|
168
286
|
|
|
169
|
-
After calling `helper.getProducer()`, you have full access to the `Producer` class
|
|
287
|
+
After calling `helper.getProducer()`, you have full access to the `Producer` class.
|
|
170
288
|
|
|
171
289
|
### `producer.send(options)`
|
|
172
290
|
|
|
@@ -257,11 +375,13 @@ Close the producer connection.
|
|
|
257
375
|
|
|
258
376
|
## Key Partitioning
|
|
259
377
|
|
|
260
|
-
By default, `@platformatic/kafka` uses **murmur2 hashing** on the message key to
|
|
378
|
+
By default, `@platformatic/kafka` uses **murmur2 hashing** on the message key to pick the target partition:
|
|
261
379
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
380
|
+
| Key | Target partition |
|
|
381
|
+
|---|---|
|
|
382
|
+
| Same key, every time | Same partition - ordering is guaranteed per key |
|
|
383
|
+
| `undefined` | Round-robin across partitions |
|
|
384
|
+
| Explicit `partition` field | That partition, overriding the partitioner |
|
|
265
385
|
|
|
266
386
|
```typescript
|
|
267
387
|
// Custom partitioner
|
|
@@ -272,3 +392,17 @@ await producer.send({
|
|
|
272
392
|
},
|
|
273
393
|
});
|
|
274
394
|
```
|
|
395
|
+
|
|
396
|
+
## See also
|
|
397
|
+
|
|
398
|
+
- [Kafka Overview](./) - the four helpers, shared health/close API, and the compile-binary caveat
|
|
399
|
+
- [Consumer](./consumer) - the receiving side, including message callbacks and lag monitoring
|
|
400
|
+
- [Schema Registry](./schema-registry) - schema-validated serialization instead of manual `serializers`
|
|
401
|
+
- [Compiling to a Single Binary](./compile-binary) - required when this helper ships inside a `bun build --compile` binary
|
|
402
|
+
- [Examples & Troubleshooting](./examples) - IoC wiring and the common connection-error lookup table
|
|
403
|
+
|
|
404
|
+
**Files:**
|
|
405
|
+
|
|
406
|
+
- [`packages/helpers/src/modules/queue/kafka/producer.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/queue/kafka/producer.ts) - `KafkaProducerHelper`
|
|
407
|
+
- [`packages/helpers/src/modules/queue/kafka/base.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/queue/kafka/base.ts) - `BaseKafkaHelper`, shared health tracking and shutdown
|
|
408
|
+
- [`packages/helpers/src/modules/queue/kafka/common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/queue/kafka/common/types.ts) - `IKafkaProducerOptions`, `IKafkaConnectionOptions`, `IKafkaTransactionContext`
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Kafka Schema Registry
|
|
3
|
+
description: KafkaSchemaRegistryHelper - schema-validated serialization for Avro, Protobuf, and JSON Schema
|
|
4
|
+
difficulty: intermediate
|
|
5
|
+
---
|
|
6
|
+
|
|
1
7
|
# Schema Registry
|
|
2
8
|
|
|
3
9
|
The `KafkaSchemaRegistryHelper` wraps `@platformatic/kafka`'s `ConfluentSchemaRegistry`. It provides a centralized schema registry that auto-serializes/deserializes messages using registered schemas (Avro, Protobuf, JSON Schema).
|
|
@@ -12,7 +18,10 @@ class KafkaSchemaRegistryHelper<
|
|
|
12
18
|
```
|
|
13
19
|
|
|
14
20
|
> [!NOTE]
|
|
15
|
-
> `KafkaSchemaRegistryHelper` extends `BaseHelper` directly (not `BaseKafkaHelper`)
|
|
21
|
+
> `KafkaSchemaRegistryHelper` extends `BaseHelper` directly (not `BaseKafkaHelper`) - it has no broker connection or health tracking. It's a configuration wrapper, not a client.
|
|
22
|
+
|
|
23
|
+
> [!WARNING]
|
|
24
|
+
> Compiling to a standalone binary needs `platformaticRequirePlugin()`. `ConfluentSchemaRegistry` resolves `ajv-draft-04` through `createRequire` at module load, which `bun build --compile` cannot see through. See [Compiling to a Single Binary](./compile-binary).
|
|
16
25
|
|
|
17
26
|
## Helper API
|
|
18
27
|
|
|
@@ -33,27 +42,35 @@ interface IKafkaSchemaRegistryOptions extends ConfluentSchemaRegistryOptions {
|
|
|
33
42
|
|
|
34
43
|
| Option | Type | Default | Description |
|
|
35
44
|
|--------|------|---------|-------------|
|
|
36
|
-
| `url` | `string` |
|
|
37
|
-
| `auth` | `{ username: string; password: string }` |
|
|
38
|
-
| `protobufTypeMapper` | `ProtobufTypeMapper` |
|
|
39
|
-
| `jsonValidateSend` | `boolean` |
|
|
45
|
+
| `url` | `string` | - | Schema registry URL. **Required** |
|
|
46
|
+
| `auth` | `{ username: string; password: string }` | - | Basic auth credentials |
|
|
47
|
+
| `protobufTypeMapper` | `ProtobufTypeMapper` | - | Custom Protobuf type mapper |
|
|
48
|
+
| `jsonValidateSend` | `boolean` | - | Validate JSON schema on produce |
|
|
40
49
|
| `identifier` | `string` | `'kafka-schema-registry'` | Scoped logging identifier |
|
|
41
50
|
|
|
42
|
-
## What
|
|
51
|
+
## What it solves
|
|
43
52
|
|
|
44
|
-
Without a schema registry, producers and consumers must agree on message
|
|
53
|
+
Without a schema registry, producers and consumers must agree on message shape out-of-band. If the producer changes the shape of `value` (adds/removes fields), consumers break silently at runtime.
|
|
45
54
|
|
|
46
|
-
**Schema Registry
|
|
55
|
+
- **Schema Registry is a centralized server** (Confluent Schema Registry) that stores and validates schemas.
|
|
56
|
+
- **It enforces a contract on the way out.** The producer says "I want to send this shape." The registry validates that shape against the registered schema before the message reaches Kafka.
|
|
57
|
+
- **It enforces a contract on the way in.** The consumer asks "what shape is this?" The registry answers with how to deserialize it.
|
|
47
58
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
59
|
+
| | Without registry | With registry |
|
|
60
|
+
|---|---|---|
|
|
61
|
+
| **Message format** | Raw string, manual `JSON.stringify`/`JSON.parse` | Typed object, auto ser/deser |
|
|
62
|
+
| **Validation** | None - runtime crashes on shape drift | Schema validated before send |
|
|
63
|
+
| **Schema evolution** | Breaks consumers silently | Backward/forward compatibility enforced |
|
|
64
|
+
| **Where schemas live** | Nowhere (tribal knowledge) | Centralized server, e.g. `http://registry:8081` |
|
|
65
|
+
|
|
66
|
+
Use it when you need schema enforcement and compatibility checks across producers and consumers, especially in multi-team environments. Skip it for simple string or JSON messages where one team controls both sides - coordinate format changes by hand instead.
|
|
52
67
|
|
|
53
|
-
|
|
68
|
+
## Without vs. with the registry
|
|
69
|
+
|
|
70
|
+
Without a registry, serialization is entirely manual and unchecked:
|
|
54
71
|
|
|
55
72
|
```typescript
|
|
56
|
-
// Producer
|
|
73
|
+
// Producer - manually serialize
|
|
57
74
|
const producer = KafkaProducerHelper.newInstance({
|
|
58
75
|
bootstrapBrokers: ['127.0.0.1:29092'],
|
|
59
76
|
clientId: 'order-producer',
|
|
@@ -63,11 +80,11 @@ await producer.getProducer().send({
|
|
|
63
80
|
messages: [{
|
|
64
81
|
topic: 'orders',
|
|
65
82
|
key: 'order-1',
|
|
66
|
-
value: JSON.stringify({ id: 1, total: 99.99 }), // <-
|
|
83
|
+
value: JSON.stringify({ id: 1, total: 99.99 }), // <- plain string, no validation
|
|
67
84
|
}],
|
|
68
85
|
});
|
|
69
86
|
|
|
70
|
-
// Consumer
|
|
87
|
+
// Consumer - manually deserialize, hope the shape is correct
|
|
71
88
|
const consumer = KafkaConsumerHelper.newInstance({
|
|
72
89
|
bootstrapBrokers: ['127.0.0.1:29092'],
|
|
73
90
|
clientId: 'order-consumer',
|
|
@@ -79,22 +96,28 @@ const consumer = KafkaConsumerHelper.newInstance({
|
|
|
79
96
|
});
|
|
80
97
|
```
|
|
81
98
|
|
|
82
|
-
|
|
99
|
+
If the producer adds `{ id: 1, total: 99.99, currency: 'USD' }` or removes `total`, the consumer has no way to know until it crashes.
|
|
83
100
|
|
|
84
|
-
|
|
101
|
+
With a registry, both sides pass `registry` instead of `serializers`/`deserializers`:
|
|
85
102
|
|
|
86
103
|
```typescript
|
|
87
|
-
|
|
104
|
+
import {
|
|
105
|
+
KafkaSchemaRegistryHelper,
|
|
106
|
+
KafkaProducerHelper,
|
|
107
|
+
KafkaConsumerHelper,
|
|
108
|
+
} from '@venizia/ignis-helpers/kafka';
|
|
109
|
+
|
|
110
|
+
// 1. Create registry - points to Confluent Schema Registry server
|
|
88
111
|
const registry = KafkaSchemaRegistryHelper.newInstance({
|
|
89
112
|
url: 'http://localhost:8081',
|
|
90
113
|
// auth: { username: 'user', password: 'pass' }, // optional
|
|
91
114
|
});
|
|
92
115
|
|
|
93
|
-
// 2. Producer
|
|
116
|
+
// 2. Producer - pass registry, it auto-serializes values using the registered schema
|
|
94
117
|
const producer = KafkaProducerHelper.newInstance({
|
|
95
118
|
bootstrapBrokers: ['127.0.0.1:29092'],
|
|
96
119
|
clientId: 'order-producer',
|
|
97
|
-
registry: registry.getRegistry(),
|
|
120
|
+
registry: registry.getRegistry(),
|
|
98
121
|
});
|
|
99
122
|
|
|
100
123
|
await producer.getProducer().send({
|
|
@@ -106,61 +129,11 @@ await producer.getProducer().send({
|
|
|
106
129
|
});
|
|
107
130
|
// If the value doesn't match the registered schema -> error BEFORE sending to Kafka
|
|
108
131
|
|
|
109
|
-
// 3. Consumer
|
|
132
|
+
// 3. Consumer - pass the same registry, it auto-deserializes
|
|
110
133
|
const consumer = KafkaConsumerHelper.newInstance({
|
|
111
134
|
bootstrapBrokers: ['127.0.0.1:29092'],
|
|
112
135
|
clientId: 'order-consumer',
|
|
113
136
|
groupId: 'order-group',
|
|
114
|
-
registry: registry.getRegistry(), // <- registry handles deserialization
|
|
115
|
-
onMessage: async ({ message }) => {
|
|
116
|
-
// message.value is already a typed object, not a raw string
|
|
117
|
-
console.log(message.value.id, message.value.total);
|
|
118
|
-
},
|
|
119
|
-
});
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
### Comparison
|
|
123
|
-
|
|
124
|
-
| | Without Registry | With Registry |
|
|
125
|
-
|---|---|---|
|
|
126
|
-
| **Message format** | Raw string, manual `JSON.stringify/parse` | Typed object, auto ser/deser |
|
|
127
|
-
| **Validation** | None -- runtime crashes | Schema validated before send |
|
|
128
|
-
| **Schema evolution** | Break consumers silently | Backward/forward compatibility enforced |
|
|
129
|
-
| **Where schemas live** | Nowhere (tribal knowledge) | Centralized server `http://registry:8081` |
|
|
130
|
-
|
|
131
|
-
You only need it when you want **schema enforcement** across producers/consumers. For simple string messages, skip it entirely.
|
|
132
|
-
|
|
133
|
-
## Basic Usage
|
|
134
|
-
|
|
135
|
-
```typescript
|
|
136
|
-
import { KafkaSchemaRegistryHelper, KafkaProducerHelper, KafkaConsumerHelper } from '@venizia/ignis-helpers/kafka';
|
|
137
|
-
|
|
138
|
-
// 1. Create registry -- points to Confluent Schema Registry server
|
|
139
|
-
const registry = KafkaSchemaRegistryHelper.newInstance({
|
|
140
|
-
url: 'http://localhost:8081',
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
// 2. Producer -- registry auto-serializes values using registered schema
|
|
144
|
-
const producer = KafkaProducerHelper.newInstance({
|
|
145
|
-
bootstrapBrokers: ['localhost:9092'],
|
|
146
|
-
clientId: 'order-producer',
|
|
147
|
-
registry: registry.getRegistry(),
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
await producer.getProducer().send({
|
|
151
|
-
messages: [{
|
|
152
|
-
topic: 'orders',
|
|
153
|
-
key: 'order-1',
|
|
154
|
-
value: { id: 1, total: 99.99 }, // object, not string -- registry serializes
|
|
155
|
-
}],
|
|
156
|
-
});
|
|
157
|
-
// If value doesn't match the registered schema -> error BEFORE sending to Kafka
|
|
158
|
-
|
|
159
|
-
// 3. Consumer -- registry auto-deserializes
|
|
160
|
-
const consumer = KafkaConsumerHelper.newInstance({
|
|
161
|
-
bootstrapBrokers: ['localhost:9092'],
|
|
162
|
-
clientId: 'order-consumer',
|
|
163
|
-
groupId: 'order-group',
|
|
164
137
|
registry: registry.getRegistry(),
|
|
165
138
|
onMessage: async ({ message }) => {
|
|
166
139
|
// message.value is already a typed object, not a raw string
|
|
@@ -171,7 +144,7 @@ const consumer = KafkaConsumerHelper.newInstance({
|
|
|
171
144
|
await consumer.start({ topics: ['orders'] });
|
|
172
145
|
```
|
|
173
146
|
|
|
174
|
-
## With
|
|
147
|
+
## With authentication
|
|
175
148
|
|
|
176
149
|
```typescript
|
|
177
150
|
const registry = KafkaSchemaRegistryHelper.newInstance({
|
|
@@ -183,9 +156,9 @@ const registry = KafkaSchemaRegistryHelper.newInstance({
|
|
|
183
156
|
});
|
|
184
157
|
```
|
|
185
158
|
|
|
186
|
-
## Alternative:
|
|
159
|
+
## Alternative: manual serializers
|
|
187
160
|
|
|
188
|
-
Instead of passing the full registry
|
|
161
|
+
Instead of passing the full registry to `registry`, extract serializers/deserializers for manual use alongside `serializers`/`deserializers`:
|
|
189
162
|
|
|
190
163
|
```typescript
|
|
191
164
|
const registry = KafkaSchemaRegistryHelper.newInstance({
|
|
@@ -204,11 +177,18 @@ const consumer = KafkaConsumerHelper.newInstance({
|
|
|
204
177
|
clientId: 'my-consumer',
|
|
205
178
|
groupId: 'my-group',
|
|
206
179
|
deserializers: registry.getDeserializers(),
|
|
207
|
-
onMessage: async ({ message }) => { ... },
|
|
180
|
+
onMessage: async ({ message }) => { /* ... */ },
|
|
208
181
|
});
|
|
209
182
|
```
|
|
210
183
|
|
|
211
|
-
##
|
|
184
|
+
## See also
|
|
185
|
+
|
|
186
|
+
- [Kafka Overview](./) - the four helpers, shared health/close API, and the compile-binary caveat
|
|
187
|
+
- [Producer](./producer) - `registry` as a producer option, plus the manual `serializers` alternative
|
|
188
|
+
- [Consumer](./consumer) - `registry` as a consumer option, plus the manual `deserializers` alternative
|
|
189
|
+
- [Examples & Troubleshooting](./examples) - IoC wiring and the common connection-error lookup table
|
|
190
|
+
|
|
191
|
+
**Files:**
|
|
212
192
|
|
|
213
|
-
-
|
|
214
|
-
-
|
|
193
|
+
- [`packages/helpers/src/modules/queue/kafka/schema/registry.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/queue/kafka/schema/registry.ts) - `KafkaSchemaRegistryHelper`
|
|
194
|
+
- [`packages/helpers/src/modules/queue/kafka/common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/queue/kafka/common/types.ts) - `IKafkaSchemaRegistryOptions`
|