Apache Kafka client library for PascalAI. Produce and consume messages, consumer groups, delivery reports, topic metadata, partition management — all via the battle-tested librdkafka C library used by every major language's Kafka binding.
Ubuntu/Debian: sudo apt install librdkafka-dev • macOS: brew install librdkafka
Create a producer, send keyed messages for consistent partition routing, then flush and destroy.
uses librdkafka;
var prod := NewProducer('broker1:9092,broker2:9092');
{ Send messages with a key for partitioning }
ProduceKeyed(prod, 'orders', 'user-42', '{"id":1001,"total":99.90}', -1);
ProduceKeyed(prod, 'orders', 'user-17', '{"id":1002,"total":14.50}', -1);
{ Wait for all deliveries }
Flush(prod, 5000);
DestroyProducer(prod);
Create a consumer, subscribe to one or more topics, then poll in a loop and commit offsets after processing.
uses librdkafka;
var cons := NewConsumer('broker1:9092', 'my-group');
Subscribe(cons, ['orders', 'events']);
while True do
begin
var msg := Poll(cons, 1000);
if not msg.IsError then
begin
WriteLn('Topic: ' + msg.Topic + ' Key: ' + msg.Key);
WriteLn('Value: ' + msg.Value);
CommitMessage(cons, msg);
end;
end;
| Function | Description |
|---|---|
| NewProducer(brokers) | Create a producer connected to the given comma-separated broker list. Returns a producer handle. |
| NewProducerEx(brokers, config) | Create a producer with an extended configuration record (acks, compression, linger.ms, etc.). |
| DestroyProducer(prod) | Release all resources held by the producer. Call after Flush to ensure no messages are lost. |
| Produce(prod, topic, value, partition) | Enqueue a message with no key. Pass -1 as partition to use automatic partitioning. |
| ProduceKeyed(prod, topic, key, value, partition) | Enqueue a message with an explicit key. Messages with the same key are routed to the same partition. |
| ProduceBatch(prod, topic, messages) | Enqueue a List<TKafkaMessage> in a single call. More efficient than looping over Produce. |
| Flush(prod, timeoutMs) | Block until all enqueued messages are delivered or the timeout expires. Returns the number of messages still in the queue. |
| OutQueueLen(prod) | Return the current number of messages waiting in the producer queue (not yet delivered). |
| PollProducer(prod, timeoutMs) | Serve delivery-report callbacks without blocking. Call periodically in high-throughput loops. |
| GetDeliveryReports(prod) | Return a List<TDeliveryReport> of completed deliveries since the last call. Each report contains topic, partition, offset, key, and error status. |
| Function | Description |
|---|---|
| NewConsumer(brokers, groupId) | Create a consumer joined to the specified consumer group. Handles automatic partition rebalancing. |
| NewConsumerEx(brokers, groupId, config) | Create a consumer with extended configuration (auto.offset.reset, session.timeout.ms, etc.). |
| DestroyConsumer(cons) | Close the consumer, commit pending offsets, and release all resources. |
| Subscribe(cons, topics) | Subscribe to a list of topics with automatic partition assignment managed by the broker. |
| Unsubscribe(cons) | Remove all topic subscriptions from this consumer. |
| Assign(cons, partitions) | Manually assign a specific list of TTopicPartition records (bypasses group rebalancing). |
| Poll(cons, timeoutMs) | Fetch the next message, waiting up to timeoutMs milliseconds. Returns a TKafkaMessage; check msg.IsError and msg.IsTimeout. |
| PollBatch(cons, maxMessages, timeoutMs) | Fetch up to maxMessages in one call. Returns a List<TKafkaMessage>. |
| CommitSync(cons) | Synchronously commit the current partition offsets for all assigned partitions. |
| CommitMessage(cons, msg) | Commit the offset of a specific message. Preferred over CommitSync for per-message acknowledgement. |
| SeekPartition(cons, topic, partition, offset) | Seek a specific partition to a given offset. Use -2 for earliest, -1 for latest. |
| PausePartitions(cons, partitions) | Pause fetching from a list of TTopicPartition records without leaving the consumer group. |
| ResumePartitions(cons, partitions) | Resume fetching from previously paused partitions. |
| GetAssignment(cons) | Return the current partition assignment as a List<TTopicPartition>. |
| Function | Description |
|---|---|
| ListTopics(handle, timeoutMs) | Return a List<TTopicInfo> describing all topics visible to this producer or consumer handle. Each record includes name, partition count, and replication factor. |
| GetPartitionCount(handle, topic) | Return the number of partitions for the given topic as an Integer. Useful for manual partition key routing. |
| GetWatermarks(handle, topic, partition) | Return a TWatermarks record with Low (earliest available) and High (latest) offsets for the specified topic-partition. |
uses librdkafka;
var prod := NewProducer('broker1:9092');
{ Inspect cluster topology }
var topics := ListTopics(prod, 5000);
for t in topics do
WriteLn(t.Name + ' — ' + IntToStr(t.PartitionCount) + ' partitions');
{ Check how much data is waiting on a partition }
var wm := GetWatermarks(prod, 'orders', 0);
WriteLn('orders[0] lag window: ' + IntToStr(wm.High - wm.Low));
DestroyProducer(prod);
groupId form a consumer group. The broker assigns each partition to exactly one member of the group, distributing load automatically. When members join or leave, a rebalance redistributes partitions. Use Assign to opt out of group management.
GetDeliveryReports or PollProducer to retrieve them. Each report carries the final offset, partition, and any error code.
CommitMessage for at-least-once semantics (commit after processing) or CommitSync to commit the entire current position. Seek to replay or skip messages.
Poll delivery reports after producing to confirm each message reached the broker and capture its final offset and partition assignment.
uses librdkafka;
var prod := NewProducer('broker1:9092,broker2:9092');
{ Enqueue a batch of messages }
ProduceKeyed(prod, 'payments', 'txn-001', '{"amount":250.00}', -1);
ProduceKeyed(prod, 'payments', 'txn-002', '{"amount":75.50}', -1);
ProduceKeyed(prod, 'payments', 'txn-003', '{"amount":1200.00}', -1);
{ Drive the event loop until all messages are delivered }
while OutQueueLen(prod) > 0 do
begin
PollProducer(prod, 100);
var reports := GetDeliveryReports(prod);
for r in reports do
begin
if r.Error = '' then
WriteLn('Delivered key=' + r.Key +
' partition=' + IntToStr(r.Partition) +
' offset=' + IntToStr(r.Offset))
else
WriteLn('FAILED key=' + r.Key + ' error: ' + r.Error);
end;
end;
DestroyProducer(prod);
Use PollBatch and commit only after the entire batch is processed for higher throughput with controlled at-least-once guarantees.
uses librdkafka;
var cons := NewConsumer('broker1:9092', 'analytics-group');
Subscribe(cons, ['payments']);
while True do
begin
var batch := PollBatch(cons, 100, 500);
if batch.Count > 0 then
begin
WriteLn('Processing ' + IntToStr(batch.Count) + ' messages');
for msg in batch do
begin
if not msg.IsError then
ProcessPayment(msg.Value);
end;
{ Commit the entire batch in one round-trip }
CommitSync(cons);
end;
end;
Rewind a partition to reprocess historical messages or skip ahead past a known bad range.
uses librdkafka;
var cons := NewConsumer('broker1:9092', 'replay-group');
{ Manually assign partition 0 of 'events' }
Assign(cons, [TopicPartition('events', 0)]);
{ Seek to a specific offset to replay from there }
SeekPartition(cons, 'events', 0, 8000);
var msg := Poll(cons, 2000);
WriteLn('Replaying from offset: ' + IntToStr(msg.Offset));
{ Check available range }
var wm := GetWatermarks(cons, 'events', 0);
WriteLn('Available range: [' + IntToStr(wm.Low) + ', ' + IntToStr(wm.High) + ']');
DestroyConsumer(cons);