rabbitmq-go

module
v0.1.2 Latest Latest
Warning

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

Go to latest
Published: Jun 16, 2026 License: MIT

README

rabbitmq-go

CI Go Reference Latest Release License

A small RabbitMQ AMQP 0-9-1 wrapper for Go. It packages connection management, publisher confirms, channel reuse, consumer retries, dead-lettering, logging and optional instrumentation into a reusable library.

This was built since I couldn't find a library that fit my needs and I had the same implmentation across multiple projects.

This project is pre-v1. APIs may change while the package hardens for broader open-source use.

Packages

pkg/rabbitmq      # core library; no OpenTelemetry dependency
pkg/otelrabbitmq  # optional first-party OpenTelemetry adapter; separate module
integration       # broker-backed integration tests; separate module

Install the core library:

go get github.com/Midwayne/rabbitmq-go/pkg/rabbitmq

Install optional OpenTelemetry support:

go get github.com/Midwayne/rabbitmq-go/pkg/otelrabbitmq

All modules target Go 1.26+.

Publishing

pub, err := rabbitmq.NewPublisher(rabbitmq.Config{
    URL:      "amqp://guest:guest@localhost:5672/",
    Exchange: "events",
})
if err != nil {
    log.Fatal(err)
}
defer pub.Close()

err = pub.Publish(ctx, "events", "user.created", []byte(`{"id":1}`), true)

For headers, properties, mandatory routing, or non-default exchanges, use PublishMessage:

err = pub.PublishMessage(ctx, rabbitmq.PublishMessage{
    RoutingKey:     "user.created",
    Body:           body,
    Headers:        amqp.Table{"schema": "user.created.v1"},
    ContentType:    "application/json",
    CorrelationID:  correlationID,
    MessageID:      messageID,
    Mandatory:      true,
    WaitForConfirm: true,
})

A publisher confirm ack means RabbitMQ accepted the publish on the channel. It does not prove the message routed to a queue. Use Mandatory: true and handle *rabbitmq.PublishReturnedError when unroutable messages must be detected.

Config.Exchange is the exchange declared by NewPublisher unless SkipExchangeDeclare is true. PublishMessage.Exchange defaults to Config.Exchange; if callers publish to another exchange, they are responsible for ensuring that exchange exists.

ChannelPoolSize is a max idle-channel cache size, not a concurrency cap. GetChannel and ReturnChannel remain available for advanced low-level uses, but callers must not use borrowed channels concurrently and must return each borrowed channel exactly once.

When queues must exist before any consumer has started — so early publishes are buffered instead of dropped as unroutable — declare them from the publisher side:

if err := pub.DeclareQueueTopology("events-worker", "user.created"); err != nil {
    log.Fatal(err)
}

DeclareQueueTopology declares the same durable queue, bindings, and dead-letter topology a Consumer declares in Consume, so whichever side declares first, the other redeclares without a conflict. Declarations are idempotent.

Consuming

consumer, err := rabbitmq.NewConsumer(ctx, rabbitmq.Config{
    URL:           "amqp://guest:guest@localhost:5672/",
    Exchange:      "events",
    PrefetchCount: 10,
    MaxRetries:    3,
})
if err != nil {
    log.Fatal(err)
}
defer consumer.Close()

handler := func(ctx context.Context, msg rabbitmq.Message) error {
    var event UserCreated
    if err := json.Unmarshal(msg.Body, &event); err != nil {
        return rabbitmq.NewNonRetryableError(err)
    }
    return process(ctx, event, msg.CorrelationID)
}

go func() { _ = consumer.Consume("events-worker", "user.*", handler) }()

Message includes body, headers, content properties, routing key, exchange, redelivery flag and retry count. Ack/nack methods are intentionally not exposed; the library owns acknowledgement semantics.

Retry behavior is at-least-once. On handler error, the consumer republishes a retry copy first and waits for publisher confirms before acking the original. If retry republish fails, the original is nacked with requeue so it can be redelivered. Retry copies preserve AMQP properties and the original delivery routing key, which matters for topic bindings such as user.*.

PrefetchCount defaults to 0, which means unlimited prefetch. Production consumers should set it explicitly.

Optional OpenTelemetry

The core package exposes a generic rabbitmq.Instrumentation interface and does not import OpenTelemetry. The optional pkg/otelrabbitmq module implements that interface:

instr := otelrabbitmq.New(
    otelrabbitmq.WithTracerProvider(tp),
    otelrabbitmq.WithMeterProvider(mp),
    otelrabbitmq.WithPropagator(propagation.TraceContext{}),
)

cfg := rabbitmq.Config{Instrumentation: instr}

otelrabbitmq is side-effect-free. It does not initialize exporters, configure global OpenTelemetry state, or call otel.SetTracerProvider. With no options it uses OpenTelemetry globals only as defaults.

The adapter instruments:

  • publish spans and publish errors;
  • consume spans and handler duration;
  • handler errors and dead-letter outcomes;
  • retry count attributes;
  • ack/nack/requeue/retried outcomes as consume-span attributes and metric dimensions;
  • message size attributes on publish and consume spans (no dedicated size metric);
  • trace-context injection into AMQP headers on publish;
  • trace-context extraction from AMQP headers before invoking handlers.

RabbitMQ OpenTelemetry semantic conventions are still evolving and this package is pre-v1, so span and metric names and attributes may change.

Configuration

Only URL and Exchange are required. Important production options include:

Field Notes
ExchangeType direct, topic, fanout, or headers; default direct
SkipExchangeDeclare use when exchanges are managed externally
ChannelPoolSize max idle confirm-channel cache size
MaxChannelAge total channel lifetime before replacement
PublishConfirmTimeout bound for waiting on broker confirms
PrefetchCount default 0 means unlimited
MaxRetries in-place retry count before dead-lettering
TLSClientConfig TLS, custom CAs, or mTLS
Heartbeat AMQP heartbeat interval
ClientProperties / ConnectionName connection metadata visible in RabbitMQ
SASL custom authentication mechanisms
DialTimeout / ConnectionTimeout startup connection bounds

Testing

This repository has nested Go modules. Prefer the Makefile or run commands per module; plain go test ./... from one module does not cover the others.

make test
make test-race
make vet
make installability
make integration
make cover-all   # combined core coverage across unit + integration suites

Because the integration module exercises most of the publisher/consumer/pool code through a real broker, make cover-all merges coverage across all suites with go tool covdata for an accurate figure; per-module go test -cover undercounts. Integration tests start RabbitMQ with testcontainers. Locally, Docker failures skip the integration suite unless RABBITMQ_TEST_URL points at an existing broker. In CI, Docker/testcontainers failures fail the job.

Release Notes

Because pkg/otelrabbitmq is a nested module, release both modules with their own tags:

git tag v0.1.0
git tag pkg/otelrabbitmq/v0.1.0

Before tagging, run make check, make integration, make govulncheck and make installability, then update CHANGELOG.md. See docs/RELEASING.md for the full checklist.

License

MIT. See LICENSE.

Directories

Path Synopsis
internal
amqpx
Package amqpx holds the low-level AMQP plumbing shared by the publisher and consumer: connection dialing, exchange declaration, credential-safe URL masking, trace-context propagation, and the retry-count header.
Package amqpx holds the low-level AMQP plumbing shared by the publisher and consumer: connection dialing, exchange declaration, credential-safe URL masking, trace-context propagation, and the retry-count header.
pkg
rabbitmq
Package rabbitmq is a small, production-grade wrapper around the RabbitMQ AMQP 0-9-1 client (github.com/rabbitmq/amqp091-go).
Package rabbitmq is a small, production-grade wrapper around the RabbitMQ AMQP 0-9-1 client (github.com/rabbitmq/amqp091-go).
rabbitmq/logging
Package logging defines the structured logging interface used by the rabbitmq library and ships two ready-to-use adapters: NopLogger (the default) and SlogLogger (backed by the standard library's log/slog).
Package logging defines the structured logging interface used by the rabbitmq library and ships two ready-to-use adapters: NopLogger (the default) and SlogLogger (backed by the standard library's log/slog).
otelrabbitmq module

Jump to

Keyboard shortcuts

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