mrkeyoor.com_
Sun 20 Sept 17:54 UTC
PyPIInfraupdated 20 Sept 2026

kombu review

Kombu 5.6.2 is the messaging layer used by Celery, available directly when an application needs producers and consumers without a task framework. Its `Connection`, `Exchange`, `Queue`, `Producer`, and `Consumer` objects present an AMQP-shaped API over RabbitMQ and a set of virtual transports including Redis and SQS. Serialization, declaration, retry, recovery, and connection pools sit in the same package, but broker features are not equal across transports. The current patch fixes Redis credential-provider compatibility, forwards ACL credentials through Redis Sentinel, improves Pub/Sub acknowledgement-deadline errors, and simplifies requirements around the Python 3.9 floor.

Verdict

Kombu 5.6.2 installed in 0.3 seconds and used 5 MB across 5 packages in our sandbox, but production still inherits the selected broker's delivery rules. Choose it for explicit AMQP-style messaging across supported transports; choose a broker-native client when portability would only hide important differences.

We installed it

Lab card: what happened when we installed kombuScreenshot of kombu documentation
Install✓ · 0.3s5 packages on disk · 5 MB
Importimport kombu in 0.08s · pure Python · requires Python >=3.9
Known vulns0(pip-audit)

Answers from our run

Does kombu install cleanly?

Yes. In a fresh container with an empty cache, pip install kombu finished in 0.3s, leaving 5 packages and 5 MB on disk. pip-audit reported no known vulnerabilities.

What does kombu need to run?

Python >=3.9, and nothing compiled: it is pure Python. In our run import kombu succeeded in 0.08s.

kombu or pika: which should you use?

pika: Use it for direct AMQP 0-9-1 access when RabbitMQ is the only target. Kombu 5.6.2 installed in 0.3 seconds and used 5 MB across 5 packages in our sandbox, but production still inherits the selected broker's delivery rules.

When should you not use kombu?

The product needs task decorators, scheduled jobs, task-state persistence, or worker management. Kombu moves messages and leaves that job system to Celery or another framework.

API stability4/5The 5.x line still revolves around `Connection`, `Exchange`, `Queue`, `Producer`, `Consumer`, `drain_events`, and message acknowledgement. Recent releases add transport options and repair recovery paths without replacing those objects. Operational behavior is less fixed than the imports: 5.6.2 changes Redis credential handling and Pub/Sub acknowledgement extension, and other 5.6 patches changed SQS and RabbitMQ edges.
Docs4/5The official documentation covers connections, declarations, producers, consumers, pools, serialization, retry helpers, and each transport. Its comparison table openly marks differences in topic routing, fanout, priority, TTL, and monitoring. The difficult part is synthesis: production behavior often requires reading the generic consumer page, a transport page, and the underlying broker's visibility or acknowledgement documentation together.
Maintenance4/5The repository was pushed on 2026-08-26, is not archived, and GitHub reports 231 open issues and pull requests. Release 5.6.2 shipped on 2025-12-29 with focused fixes for Redis credentials, Redis Sentinel ACL use, Pub/Sub acknowledgement deadlines, and Python requirements. Work continues under the Celery organization, though the number of transports creates a broad regression surface and a sizeable tracker.
Ecosystem5/5The supplied count is 13,404,148 weekly downloads, and GitHub reports 3,135 stars. Celery depends on Kombu, while extras cover Redis, SQS, Pub/Sub, MongoDB, Azure queues, SQLAlchemy, Kafka, and other transports. That breadth is unusual in Python messaging. It should be read as one programming model over multiple adapters, since the project's own matrix documents features that disappear on particular brokers.

Use it if

  • A Python service needs exchange, routing-key, queue, acknowledgement, and retry control without Celery's task registry or result model.
  • RabbitMQ is the current broker but a documented virtual transport may be required for another deployment.
  • Publishers need connection recovery, channel revival, or a bounded producer pool around repeated sends.
  • Unit tests can use the in-memory transport while broker integration tests exercise the actual RabbitMQ, Redis, or SQS behavior.
Skip it if

Setup reality

We installed Kombu 5.6.2 in a clean Python 3.12 Bookworm container. It completed in 0.3 seconds, left 5 packages using 5 MB, and pip-audit found 0 known vulnerabilities. import kombu took 0.08 seconds. The distribution is pure Python, requires Python 3.9 or newer, declares 27 direct dependency entries, uses BSD-3-Clause, and has no py.typed marker. The base import needs no running broker.

A useful connection does need a broker URL and, usually, credentials. Non-AMQP transports require their matching extras, such as Redis or SQS support. Treat the complete URL as a secret because usernames and passwords may be embedded in it. Extras can add platform-sensitive clients; test the chosen transport in the deployment image. Version 5.6.2 specifically repairs Redis providers older than 5.3 and ensures Sentinel master discovery receives ACL credentials.

Declare topology on both ends. A producer can pass declare=[queue], and a consumer declares its queue when entering the consumer context. Several virtual transports keep declarations in client memory rather than in a broker-native exchange model. JSON is the sensible default serializer. Kombu rejects disabled content types, and enabling pickle for messages from untrusted publishers permits Python object construction during decode.

A consumer waits in blocking drain_events and must acknowledge, reject, or requeue each delivery. Connection recovery cannot guarantee one execution: losing the link after the broker accepts a publish or before it records an acknowledgement can produce a duplicate. Handlers need idempotency. Visibility timeouts, fanout, TTL, priority, and monitoring vary by transport. Version 5.6.2 improves Pub/Sub acknowledgement-extension errors, but it does not erase those broker differences.

Patterns

Describe an exchange and bound queue declare-routing

from kombu import Exchange, Queue

events = Exchange("events", type="topic", durable=True)
audit = Queue(
    "audit.events",
    exchange=events,
    routing_key="audit.#",
    durable=True,
)

These are declarations until bound to a channel. Topic routing and durability depend on the selected transport.

Publish JSON after declaring the route publish-json

from kombu import Connection

with Connection(broker_url) as connection:
    producer = connection.Producer(serializer="json")
    producer.publish(
        {"event": "invoice.created", "id": 42},
        exchange=events,
        routing_key="audit.invoice",
        declare=[audit],
        retry=True,
    )

Publish retry covers recoverable connection errors. A connection loss after broker acceptance can still result in a duplicate send.

Consume JSON and acknowledge success consume-and-ack

def handle(body, message):
    process(body)
    message.ack()

with Connection(broker_url) as connection:
    with connection.Consumer(audit, callbacks=[handle], accept=["json"]):
        while True:
            connection.drain_events(timeout=5)

`drain_events` blocks. An exception before `ack()` may cause redelivery, so `process` must tolerate the same message twice.

Reject a permanently invalid payload reject-invalid-message

def handle(body, message):
    if "id" not in body:
        message.reject(requeue=False)
        return
    process(body)
    message.ack()

With `requeue=False`, the broker discards or dead-letters according to its configuration. Requeue only failures that another attempt may fix.

Exercise message wiring without a broker test-memory-transport

from kombu import Connection, Queue

queue = Queue("test-events")
with Connection("memory://") as connection:
    connection.Producer(serializer="json").publish(
        {"ok": True}, routing_key=queue.name, declare=[queue]
    )
    message = queue(connection).get(no_ack=True)
    assert message.payload == {"ok": True}

The memory transport is process-local and does not reproduce RabbitMQ, Redis, or SQS failure and durability behavior.

Bound startup connection retries retry-initial-connection

from kombu import Connection

connection = Connection(broker_url)
connection.ensure_connection(
    max_retries=5,
    interval_start=1,
    interval_step=2,
    interval_max=10,
)

A finite `max_retries` lets the process fail health checks instead of hanging forever while the broker is unavailable.

Retry an operation on a revived channel revive-producer

with Connection(broker_url) as connection:
    producer = connection.Producer(serializer="json")
    publish = connection.ensure(producer, producer.publish, max_retries=3)
    publish(
        {"id": 42},
        exchange=events,
        routing_key="audit.created",
        declare=[audit],
    )

`ensure` can replace a broken connection and channel. It cannot tell whether the broker accepted the last attempt before disconnection.

Set Redis visibility and polling options configure-redis-transport

from kombu import Connection

connection = Connection(
    "redis://localhost:6379/0",
    transport_options={
        "visibility_timeout": 3600,
        "polling_interval": 2,
        "client_name": "billing-consumer",
    },
)

These options are Redis-specific. Set visibility above the expected processing time or long handlers can be delivered again while still running.

Reuse a producer from the global pool borrow-producer

from kombu import Connection
from kombu.pools import producers

connection = Connection(broker_url)
with producers[connection].acquire(block=True) as producer:
    producer.publish(
        {"id": 42},
        exchange=events,
        routing_key="audit.created",
        declare=[audit],
        serializer="json",
    )

The context returns the producer after success or failure. Pool identity follows the connection settings used as the key.

Send an already encoded byte payload publish-bytes

with Connection(broker_url) as connection:
    connection.Producer().publish(
        b"encoded-payload",
        exchange=events,
        routing_key="audit.raw",
        content_type="application/octet-stream",
        content_encoding="binary",
        declare=[audit],
    )

When bypassing serializers, set content metadata and make the consumer accept and decode that exact type.

Bind a queue before declaring it bind-and-declare

from kombu import Connection

with Connection(broker_url) as connection:
    with connection.channel() as channel:
        bound = audit(channel)
        bound.declare()

Calling broker methods on an unbound `Queue` raises `NotBoundError`; binding returns a channel-specific copy.

Consume two routes on one channel consume-two-queues

with Connection(broker_url) as connection:
    with connection.Consumer(
        [audit_queue, billing_queue],
        callbacks=[handle],
        accept=["json"],
        prefetch_count=20,
    ):
        while True:
            connection.drain_events(timeout=5)

The prefetch count applies to deliveries held by this consumer channel; tune it against handler duration and fairness.

Alternatives

PackageRegistryPick it when
pikaPyPIUse it for direct AMQP 0-9-1 access when RabbitMQ is the only target.
aio-pikaPyPIUse it when RabbitMQ producers and consumers must live natively in asyncio.
redisPyPIUse Redis lists or streams directly when one Redis-specific queue model is enough.

More infra guides

boto3 · opentelemetry-api · psutil · distro · @opentelemetry/api · google-cloud-storage · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.