kafka

package module
v0.0.0-...-3898f95 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 17, 2026 License: BSD-3-Clause Imports: 6 Imported by: 0

README

go-ruby-kafka/kafka

kafka — go-ruby-kafka

Docs License Go Coverage

A pure-Go (no cgo), MRI-faithful reimplementation of the Ruby ruby-kafka gem's client surface — the object model a Ruby program drives when it calls Kafka.new, kafka.producer, kafka.consumer and the topic-admin helpers. It mirrors the gem's method names and semantics: a buffering producer with produce / deliver_messages, a one-shot deliver_message, a consumer-group consumer with subscribe / each_message / each_batch / commit_offsets / stop, and create_topic / topics / partitions_for / delete_topic.

It is the Kafka backend for go-embedded-ruby, but is a standalone, reusable module — a sibling of go-ruby-redis and go-ruby-pg.

What it is — and what it consumes. The Kafka wire protocol is not reimplemented here (the common rdkafka gem is a C extension). Instead this package binds the pure-Go franz-go client (kgo + kadm) for the protocol, and wraps it in ruby-kafka's shape. The broker connection is a host seam: the constructors that dial a broker are injectable, so the test suite runs deterministic round-trips against the in-process kfake broker — no external Kafka — and drives the error branches through a mock.

Surface

  • ClientNew(Options{SeedBrokers, ClientID})*Kafka, mirroring Kafka.new(seed_brokers:, client_id:).
  • Producerkafka.Producer()Producer; Produce(value, ProduceOptions{Topic, Key, Partition, Headers}) buffers, DeliverMessages() flushes, Shutdown() closes. The synchronous one-shot is kafka.DeliverMessage(value, topic). An explicit Partition is honoured; otherwise records balance by key hash.
  • Consumerkafka.Consumer(groupID)Consumer; Subscribe(topic, startFromBeginning), the poll loops EachMessage(func(*Message) error) and EachBatch(func(*Batch) error), explicit CommitOffsets(), and Stop(). A Message carries the subject-like Topic plus Partition / Offset / Key / Value / Headers / CreateTime.
  • AdminCreateTopic(name, numPartitions, replicationFactor), Topics(), PartitionsFor(name), DeleteTopic(name).
  • Errors — the Kafka::*Error tree: ErrDeliveryFailed, ErrConnection, ErrUnknownTopicOrPartition, ErrOffsetCommit, ErrOffsetOutOfRange. Every returned error wraps one of these sentinels (classify with errors.Is) and the underlying franz-go/kerr error.

Usage

import "github.com/go-ruby-kafka/kafka"

k := kafka.New(kafka.Options{SeedBrokers: []string{"localhost:9092"}, ClientID: "app"})
defer k.Close()

k.CreateTopic("orders", 3, 1)

// Producer: buffer, then deliver.
p := k.Producer()
defer p.Shutdown()
p.Produce([]byte(`{"id":1}`), kafka.ProduceOptions{Topic: "orders", Key: []byte("1")})
p.DeliverMessages()

// Or a one-shot synchronous send.
k.DeliverMessage([]byte("ping"), "orders")

// Consumer group: subscribe and iterate.
c := k.Consumer("billing")
c.Subscribe("orders", true) // start_from_beginning
c.EachMessage(func(m *kafka.Message) error {
    process(m.Topic, m.Partition, m.Offset, m.Value)
    return c.CommitOffsets()
})

Tests & coverage

The suite holds 100% statement coverage with -race. Two layers reach it:

  • kfake round-trips — an in-process fake Kafka cluster (kfake) exercises the real franz-go producer / consumer / admin: produce→consume delivers the correct key / value / headers / partition / offset, a consumer group resumes after a committed offset, and topic create / list / partitions / delete are verified as real round-trips.
  • Deterministic mock — the broker seam is replaced by a mock to drive every error branch (delivery failure, connection loss, unknown topic, offset-commit and offset-out-of-range mapping) without any network.

The kfake round-trips run on the native CI lanes (Linux/macOS/Windows and amd64/arm64). Under qemu-user emulation a full protocol broker is too heavy, so the cross-arch lanes set GO_RUBY_KAFKA_KFAKE=0 and run the mock suite; the coverage gate is met on the native lanes where kfake executes.

GOWORK=off go test -race ./...          # full suite (kfake + mock)
GO_RUBY_KAFKA_KFAKE=0 go test ./...     # deterministic mock suite only

Validated CGO-free on all six supported 64-bit targets — amd64, arm64, riscv64, loong64, ppc64le and s390x (big-endian) — across Linux, macOS and Windows.

License

BSD-3-Clause — see LICENSE. Copyright the go-ruby-kafka/kafka authors.

WebAssembly

Being pure Go (CGO=0), this library also compiles to WebAssembly — both GOOS=js GOARCH=wasm (browser / Node.js) and GOOS=wasip1 GOARCH=wasm (WASI). CI builds both targets on every push, alongside the six 64-bit native/qemu arches.

GOOS=js     GOARCH=wasm go build ./...   # browser / Node
GOOS=wasip1 GOARCH=wasm go build ./...   # WASI (wasmtime, wasmer, wasmedge, …)

Documentation

Overview

Package kafka is a pure-Go (CGO-free), MRI-faithful reimplementation of the Ruby ruby-kafka gem's client surface — the object model a Ruby program drives when it calls Kafka.new, kafka.producer, kafka.consumer and the topic admin helpers.

It mirrors the gem's method names and semantics:

The Kafka wire protocol is NOT reimplemented here. This package consumes the pure-Go franz-go client (kgo + kadm) for the protocol and, in its tests, the in-process kfake broker for deterministic round-trips with no external Kafka. The broker connection is a host seam: the constructors that dial a broker are package variables, so tests inject either the real franz-go client (pointed at kfake) or a deterministic mock.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrDeliveryFailed is Kafka::DeliveryFailed — a produce did not succeed.
	ErrDeliveryFailed = errors.New("kafka: delivery failed")
	// ErrConnection is Kafka::ConnectionError — the broker could not be reached
	// or a request failed at the transport level.
	ErrConnection = errors.New("kafka: connection error")
	// ErrUnknownTopicOrPartition is Kafka::UnknownTopicOrPartition.
	ErrUnknownTopicOrPartition = errors.New("kafka: unknown topic or partition")
	// ErrOffsetCommit is Kafka::OffsetCommitError — committing consumer-group
	// offsets failed.
	ErrOffsetCommit = errors.New("kafka: offset commit error")
	// ErrOffsetOutOfRange is Kafka::OffsetOutOfRange — a fetch requested an
	// offset the broker no longer holds.
	ErrOffsetOutOfRange = errors.New("kafka: offset out of range")
)

The Kafka error tree, mirroring ruby-kafka's Kafka::*Error classes. Every error returned by this package wraps one of these sentinels, so callers can classify failures with errors.Is, e.g.:

if errors.Is(err, kafka.ErrUnknownTopicOrPartition) { ... }

Functions

This section is empty.

Types

type Batch

type Batch struct {
	Topic     string
	Partition int32
	Messages  []*Message
}

Batch is a per-(topic, partition) run of messages yielded by Consumer.EachBatch, mirroring ruby-kafka's batch object.

type Consumer

type Consumer struct {
	// contains filtered or unexported fields
}

Consumer is a consumer-group member, the analogue of the object returned by kafka.consumer(group_id:). Topics are registered with Consumer.Subscribe; the poll loop is driven by Consumer.EachMessage or Consumer.EachBatch; offsets are persisted with Consumer.CommitOffsets; and Consumer.Stop ends the loop.

func (*Consumer) CommitOffsets

func (c *Consumer) CommitOffsets() error

CommitOffsets persists the offsets of the messages yielded so far, mirroring consumer.commit_offsets. It is a no-op if nothing has been consumed.

func (*Consumer) EachBatch

func (c *Consumer) EachBatch(fn func(*Batch) error) error

EachBatch runs the poll loop, yielding a per-partition batch at a time, mirroring consumer.each_batch { |batch| ... }.

func (*Consumer) EachMessage

func (c *Consumer) EachMessage(fn func(*Message) error) error

EachMessage runs the poll loop, yielding one message at a time, mirroring consumer.each_message { |message| ... }. It returns nil after Consumer.Stop, or the error the block returns, or a connection/offset error.

func (*Consumer) Stop

func (c *Consumer) Stop()

Stop ends the poll loop, mirroring consumer.stop. It is safe to call from any goroutine.

func (*Consumer) Subscribe

func (c *Consumer) Subscribe(topic string, startFromBeginning bool)

Subscribe registers a topic for consumption, mirroring consumer.subscribe(topic, start_from_beginning:). If any subscription asks to start from the beginning, the group resets to the earliest offset when it has no committed position.

type Kafka

type Kafka struct {
	// contains filtered or unexported fields
}

Kafka is the top-level client, the analogue of the object returned by Kafka.new. It is the factory for producers and consumers and carries the topic-admin surface. A lazily-created admin connection backs the admin methods and is released by Kafka.Close.

func New

func New(o Options) *Kafka

New builds a Kafka client. It performs no I/O; connections are opened lazily by the producer, consumer and admin surfaces.

func (*Kafka) Close

func (k *Kafka) Close()

Close releases the shared admin connection, if one was opened.

func (*Kafka) Consumer

func (k *Kafka) Consumer(groupID string) *Consumer

Consumer returns a new consumer-group consumer, mirroring kafka.consumer(group_id:).

func (*Kafka) CreateTopic

func (k *Kafka) CreateTopic(name string, numPartitions int32, replicationFactor int16) error

CreateTopic creates a topic, mirroring kafka.create_topic(name, num_partitions:, replication_factor:).

func (*Kafka) DeleteTopic

func (k *Kafka) DeleteTopic(name string) error

DeleteTopic deletes a topic, mirroring kafka.delete_topic(name).

func (*Kafka) DeliverMessage

func (k *Kafka) DeliverMessage(value []byte, topic string) error

DeliverMessage sends a single message synchronously, mirroring kafka.deliver_message(value, topic:). It opens a short-lived producer, sends, and closes it.

func (*Kafka) PartitionsFor

func (k *Kafka) PartitionsFor(name string) ([]int32, error)

PartitionsFor returns the partition ids of a topic, mirroring kafka.partitions_for(name). An unknown topic yields ErrUnknownTopicOrPartition.

func (*Kafka) Producer

func (k *Kafka) Producer() *Producer

Producer returns a new buffering producer, mirroring kafka.producer.

func (*Kafka) Topics

func (k *Kafka) Topics() ([]string, error)

Topics lists the cluster's topics, mirroring kafka.topics.

type Message

type Message struct {
	Topic      string
	Partition  int32
	Offset     int64
	Key        []byte
	Value      []byte
	Headers    map[string][]byte
	CreateTime time.Time
}

Message is a consumed record, the analogue of ruby-kafka's message object. Its Topic field plays the "subject" role: it names where the message came from, alongside the partition/offset coordinates and the payload.

type Options

type Options struct {
	// SeedBrokers is the list of "host:port" bootstrap brokers.
	SeedBrokers []string
	// ClientID is the client identifier sent to the broker. Optional.
	ClientID string
}

Options configures a Kafka client, mirroring the keyword arguments of the gem's Kafka.new(seed_brokers:, client_id:).

type ProduceOptions

type ProduceOptions struct {
	// Topic is the destination topic. Required.
	Topic string
	// Key is the optional partitioning/message key.
	Key []byte
	// Partition, when non-nil, pins the message to an explicit partition;
	// otherwise the partition is chosen by key hash (or balanced).
	Partition *int32
	// Headers is the optional set of record headers.
	Headers map[string][]byte
}

ProduceOptions mirrors the keyword arguments of ruby-kafka's producer.produce(value, topic:, key:, partition:, headers:).

type Producer

type Producer struct {
	// contains filtered or unexported fields
}

Producer is a buffering producer, the analogue of the object returned by kafka.producer. Messages are buffered by Producer.Produce and flushed by Producer.DeliverMessages; Producer.Shutdown releases the connection.

func (*Producer) DeliverMessages

func (p *Producer) DeliverMessages() error

DeliverMessages flushes the buffered messages to Kafka, mirroring producer.deliver_messages. An empty buffer is a no-op. On success the buffer is cleared; on failure it is retained for a later retry.

func (*Producer) Produce

func (p *Producer) Produce(value []byte, o ProduceOptions) error

Produce buffers a message for later delivery, mirroring producer.produce(value, topic:, ...). It performs no I/O.

func (*Producer) Shutdown

func (p *Producer) Shutdown()

Shutdown closes the producer's connection, mirroring producer.shutdown.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL