All notable changes to babelqueue (Python) are documented here.
The format is based on Keep a Changelog,
and this project adheres to Semantic Versioning.
The envelope wire format is versioned separately by meta.schema_version
(currently 1) — see the contract at babelqueue.com.
1.6.0 - 2026-06-14
- Redis/Laravel reservation parity — the Redis transport can now consume a
shared Laravel BabelQueue Redis queue using Laravel's reserved-set / reliable-queue
semantics, not just a Python-owned queue. Enable it with the
laravel=1URL flag (redis://host:6379/0?laravel=1) orRedisTransport(..., laravel_compat=True). In this mode the key layout is Laravel's stock Redis queue (§1 of the broker-bindings contract): aqueues:<name>ready list, aqueues:<name>:reservedsorted set scored by aretry_afterdeadline (default 60s), aqueues:<name>:delayedset, and aqueues:<name>:notifywake-up list. Reserve, ack and release run the byte-for-byte same Lua scripts Laravel uses, so the reserved member a Python worker writes is identical to a Laravel worker's — either side can ack (ZREM) the other's reservation, so a Python worker and a Laravel worker share one Redis queue without losing or double-processing messages. Before each pop, expired reserved/delayed jobs migrate back to the ready list, so a crashed worker's in-flight job is re-reserved exactly as Laravel does. Tunable via?prefix=/?retry_after=(or thekey_prefix/retry_afterconstructor args). The default Python-owned reliable-queue mode (BLMOVE+<queue>:processinglist) is unchanged and stays the default, so existing callers are unaffected. The reservation logic is fully unit-tested with an injected in-memory Redis double (noredispackage, no broker); a live cross-runtime PHP↔Python shared-queue round-trip is covered by the integration suite where a real Redis is present. The envelope is unchanged (schema_version: 1); this is purely additive. Ships as a MINOR.
- Apache ActiveMQ Artemis transport (
babelqueue[artemis],python-qpid-proton) —ArtemisTransport, selected by theartemis://(orartemis+ssl://) URL scheme (e.g.artemis://localhost:5672; or pass an injectedconnection). Artemis speaks AMQP 1.0 (not RabbitMQ's 0-9-1), so the transport uses thepython-qpid-protonblocking client. Implements §7 of the broker-bindings contract: the canonical envelope is the message body, projected onto the AMQP fields a JMS peer reads —correlation-id=trace_id(JMSCorrelationID),creation-time=meta.created_at(JMSTimestamp), thex-opt-jms-typeannotation = URN (JMSType, the AMQP-JMS mapping), plus thebq-schema-version/bq-source-lang/bq-attempts/bq-app-idapplication properties. Consume reserves one message at a time (receive→ process →accept);attemptsis reconciled tomax(body, delivery_count)— the AMQP delivery-count header is 0-based, so it maps directly with no −1 (the Java JMS binding reads the 1-basedJMSXDeliveryCountand subtracts 1, arriving at the same 0-basedattempts), and themaxnever lowers a higher body count carried by a republish-driven retry. The projection + reconciliation + pop/ack flow are unit-tested with no broker and nopython-qpid-proton(the proton import is lazy; the transport talks to an injected connection fake); the publish flow that builds a real protonMessageis exercised wherever proton is installed. The envelope is unchanged (schema_version: 1); Apache ActiveMQ Artemis is purely additive. Ships as a MINOR.
- Apache Kafka transport (
babelqueue[kafka],confluent-kafka) —KafkaTransport, selected by thekafka://URL scheme (e.g.kafka://host:9092; or pass an injectedproducer+consumer_factory). Implements §6 of the broker-bindings contract: the record value is the canonical envelope, projected onto native Kafka record headers (UTF-8 byte strings) —bq-job= URN,bq-trace-id,bq-message-id, plusbq-schema-version/bq-source-lang/bq-attempts— with the record timestamp mirroringmeta.created_at. Consume is process-then-commit (popreserves viapollwithenable.auto.commit=false,ackcommits the offset); thebq-attemptsheader is the authoritative attempt counter (the body'sattemptsis the fallback for non-BabelQueue producers). The projection + reconciliation + publish/pop/ack flow are unit-tested with no broker and noconfluent-kafka(the kafka import is lazy; the transport talks to injected producer/consumer fakes). The envelope is unchanged (schema_version: 1); Apache Kafka is purely additive. Ships as a MINOR.
- Apache Pulsar transport (
babelqueue[pulsar],pulsar-client) —PulsarTransport, selected by thepulsar://(orpulsar+ssl://) URL scheme (e.g.pulsar://localhost:6650; or pass a builtclient). Implements §5 of the broker-bindings contract: the canonical envelope is the message payload, projected onto native Pulsar message properties (string→string) —bq-job= URN,bq-trace-id=trace_id,bq-message-id=meta.id, plusbq-schema-version/bq-source-lang/bq-attempts; receive →acknowledge;attemptsreconciled tomax(bq-attempts, redelivery_count)(Pulsar's redelivery count is 0-based, so it maps directly with no −1, and themaxnever lowers a higher body count carried by a republish-driven retry). DefaultSharedsubscription namedbabelqueue; a client can be injected for tests/DI. The projection + reconciliation + publish/pop/ack flow are unit-tested with no broker and nopulsar-client(the pulsar import is lazy and publishing sends raw bytes). The envelope is unchanged (schema_version: 1); Apache Pulsar is purely additive. Ships as a MINOR.
1.2.0 - 2026-06-13
- Azure Service Bus transport (
babelqueue[azureservicebus],azure-servicebus) —AsbTransport, selected by thesb://URL scheme (e.g.sb://<namespace>.servicebus.windows.net, Azure AD viaDefaultAzureCredential; or passconnection_string=.../ a builtclient). Implements §4 of the broker-bindings contract: the canonical envelope is the message body, projected onto native Service Bus fields (Subject= URN,CorrelationId=trace_id,MessageId=meta.id, plus thebq-application properties); PeekLock reserve →complete_messageack;attemptsreconciled to the broker-authoritativeDeliveryCount − 1. A client can be injected for tests/DI. The projection + reconciliation are unit-tested with no broker and noazure-servicebus(the azure import is lazy); the publish flow is covered with a fake client. The envelope is unchanged (schema_version: 1); Azure Service Bus is purely additive. Ships as a MINOR.
1.1.0 - 2026-06-12
- Amazon SQS transport (
babelqueue[sqs],boto3) —SqsTransport, selected by thesqs://URL scheme (e.g.sqs://us-east-1?endpoint=http://localhost:4566for LocalStack). Implements §3 of the broker-bindings contract: the canonical envelope is theMessageBody, projected onto nativeMessageAttributes(bq-job/bq-trace-id/bq-message-id/bq-schema-version/bq-source-lang/bq-created-at); visibility-timeout reserve →delete_messageack;attemptsreconciled toApproximateReceiveCount − 1(never lowering a runtime-incremented count). Supports FIFO (MessageGroupId/MessageDeduplicationId=meta.id), content-based dedup, configurable wait/visibility, and aqueue_url_prefixthat skipsGetQueueUrl. A client can be injected for tests/DI. 16 unit tests run against a fake client (no boto3, no broker); a LocalStack integration test round-trips the realboto3path. The envelope is unchanged (schema_version: 1); SQS is purely additive. Ships as a MINOR.
1.0.0 - 2026-06-07
1.0.0 — the public API is now SemVer-stable: breaking changes require a MAJOR,
following the deprecation policy. The wire envelope is unchanged
(schema_version: 1); the core + Celery/Django adapters ship together. Full
reference at babelqueue.com.
- CI adds ruff + mypy static analysis and a >=90% coverage gate
(
pytest --cov --cov-fail-under=90, run in the broker-backed job so the Redis / RabbitMQ transports count). Type-safety fix inredis_transport(str-narrow the BLMOVE reply) surfaced by mypy — no behaviour change. - GR-8 latency benchmark (
tests/test_overhead.py) — asserts the envelope encode/decode path adds ≤2% over plain-JSON serialization vs a conservative 2ms broker round-trip (the pure-Python codec is slower than the compiled SDKs — ~16µs marginal on CPython 3.9/CI — so the reference is higher to stay robust).
0.5.0 - 2026-06-06
- Celery adapter (
babelqueue.celery,[celery]extra) —from_celery(app)builds aBabelQueueruntime on a Celery app's broker, andinstall_worker(app)registers a Celery worker bootstep that drains URN-routed polyglot messages in a background thread alongside Celery's own consumer. - Django adapter (
babelqueue.django,[django]extra) — settings-drivenBABELQUEUEconfig,get_app()/publish()shortcuts, and amanage.py babelqueue_workermanagement command. Add"babelqueue.django"toINSTALLED_APPS. - Both adapters lazy-import their framework, so the core stays dependency-free.
0.4.0 - 2026-06-06
EnvelopeCodec.urn()— resolve the URN (job, acceptingurnas an alias).EnvelopeCodec.accepts()— consumer-side envelope validation (rejects empty URN, unsupportedmeta.schema_version, blanktrace_id, non-objectdata).- Shared cross-SDK conformance suite under
tests/conformance/(vendored from the canonicalconformance/set) plus atest_conformance.pyrunner.
0.3.0 - 2026-06-06
- RabbitMQ transport (
PikaTransport,amqp://): durable queue, persistent delivery,basic_get+ manual ack, and the contract AMQP properties (type=URN,correlation_id=trace_id,x-schema-version/x-source-lang/x-attempts). Optional[amqp]extra (lazypikaimport) — the core stays zero-dep.
0.2.0 - 2026-06-06
- Runtime —
BabelQueue(broker_url=...)app with a@app.handler("urn:...")decorator,publish(), and aconsume()/run()loop. Routes by URN over the canonical envelope;attempts-based retry → opt-in dead-letter queue;on_unknown_urnstrategies (fail/delete/release/dead_letter). - Transports — a pluggable
Transportabstraction withInMemoryTransport(memory://, for tests/local) andRedisTransport(redis://, reliable-queue pattern viaBLMOVE+ a processing list). Redis client is an optional[redis]extra, imported lazily — the core stays zero-dep.
0.1.0 - 2026-06-06
EnvelopeCodec— builds (make,from_message), encodes and decodes the canonical{job, trace_id, data, meta, attempts}envelope (schema_version1). The single Python implementation of the wire format.- Contracts
PolyglotMessage/HasTraceId(typedProtocols). dead_letter.annotate()— additivedead_letterblock builder.UnknownUrnStrategy—fail/delete/release/dead_letter.BabelQueueError/UnknownUrnError.- Golden conformance fixtures under
tests/fixtures/(shared cross-SDK set). py.typed— ships inline type hints (PEP 561).
- Pre-1.0: the public API may change before the
1.0.0tag. - The core has zero runtime dependencies (standard library only); Python
>=3.9.