babelqueue 1.22.0__tar.gz → 1.24.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {babelqueue-1.22.0 → babelqueue-1.24.0}/.github/workflows/ci.yml +1 -1
- {babelqueue-1.22.0 → babelqueue-1.24.0}/.github/workflows/release.yml +2 -2
- {babelqueue-1.22.0 → babelqueue-1.24.0}/CHANGELOG.md +135 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/PKG-INFO +41 -7
- {babelqueue-1.22.0 → babelqueue-1.24.0}/README.md +40 -6
- {babelqueue-1.22.0 → babelqueue-1.24.0}/pyproject.toml +1 -1
- {babelqueue-1.22.0 → babelqueue-1.24.0}/src/babelqueue/__init__.py +7 -1
- {babelqueue-1.22.0 → babelqueue-1.24.0}/src/babelqueue/_envelope_shape.py +1 -1
- {babelqueue-1.22.0 → babelqueue-1.24.0}/src/babelqueue/app.py +201 -24
- {babelqueue-1.22.0 → babelqueue-1.24.0}/src/babelqueue/artemis_transport.py +2 -1
- {babelqueue-1.22.0 → babelqueue-1.24.0}/src/babelqueue/asb_transport.py +37 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/src/babelqueue/codec.py +46 -1
- {babelqueue-1.22.0 → babelqueue-1.24.0}/src/babelqueue/kafka_transport.py +8 -2
- {babelqueue-1.22.0 → babelqueue-1.24.0}/src/babelqueue/pika_transport.py +3 -1
- {babelqueue-1.22.0 → babelqueue-1.24.0}/src/babelqueue/pulsar_transport.py +35 -2
- {babelqueue-1.22.0 → babelqueue-1.24.0}/src/babelqueue/redis_transport.py +23 -13
- {babelqueue-1.22.0 → babelqueue-1.24.0}/src/babelqueue/sqs_transport.py +40 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/src/babelqueue/transport.py +67 -0
- babelqueue-1.24.0/tests/conformance/CONFORMANCE_VERSION +1 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/manifest.json +1522 -1
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/schema/results.example.json +1 -1
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/test_app.py +137 -4
- babelqueue-1.24.0/tests/test_asb_conformance.py +177 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/test_asb_transport.py +148 -1
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/test_behaviour_conformance.py +281 -4
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/test_conformance.py +6 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/test_kafka_retry.py +56 -0
- babelqueue-1.24.0/tests/test_poison_routing.py +581 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/test_pulsar_transport.py +4 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/test_redis_transport.py +92 -5
- babelqueue-1.24.0/tests/test_sqs_conformance.py +155 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/test_sqs_transport.py +99 -13
- babelqueue-1.22.0/tests/conformance/CONFORMANCE_VERSION +0 -1
- babelqueue-1.22.0/tests/test_asb_conformance.py +0 -84
- babelqueue-1.22.0/tests/test_sqs_conformance.py +0 -80
- {babelqueue-1.22.0 → babelqueue-1.24.0}/.github/FUNDING.yml +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/.github/dependabot.yml +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/.gitignore +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/LICENSE +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/conformance-known-gaps.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/scripts/check_conformance_results.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/src/babelqueue/_poison_record.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/src/babelqueue/celery.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/src/babelqueue/contracts.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/src/babelqueue/dead_letter.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/src/babelqueue/django/__init__.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/src/babelqueue/django/apps.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/src/babelqueue/django/management/__init__.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/src/babelqueue/django/management/commands/__init__.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/src/babelqueue/django/management/commands/babelqueue_worker.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/src/babelqueue/exceptions.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/src/babelqueue/gdpr.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/src/babelqueue/headers.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/src/babelqueue/idempotency.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/src/babelqueue/kafka_retry.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/src/babelqueue/otel.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/src/babelqueue/outbox.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/src/babelqueue/py.typed +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/src/babelqueue/redrive.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/src/babelqueue/replay.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/src/babelqueue/routing.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/src/babelqueue/schema.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/blank-ascii-job-urn-fallback.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/data-array-rejected.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/dead-letter-roundtrip.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/dead-lettered.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/duplicate-keys-last-wins.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/empty-data-roundtrip.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/forbidden-key-job-and-urn.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/forbidden-key-job-nonascii-space-and-urn.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/forbidden-key-meta-attempts.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/forbidden-key-meta-max-retries.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/forbidden-key-meta-source.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/forbidden-key-meta-ts.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/forbidden-key-timestamp.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/invalid-missing-urn.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/invalid-unknown-schema-version.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/invalid-wrong-case-job.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/job-type-array-urn-fallback.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/job-type-bool-urn-fallback.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/job-type-empty-string-urn-fallback.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/job-type-missing-job-array-urn.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/job-type-null-no-urn.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/job-type-null-urn-fallback.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/job-type-number-blank-urn.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/job-type-number-nonstring-urn.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/job-type-number-urn-fallback.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/job-type-object-urn-fallback.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/meta-ext-vendor-roundtrip.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/order-created.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/trim-blank-job-cr.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/trim-blank-job-ff.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/trim-blank-job-lf.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/trim-blank-job-space.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/trim-blank-job-tab.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/trim-blank-job-vt.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/trim-blank-trace-id-cr.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/trim-blank-trace-id-ff.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/trim-blank-trace-id-lf.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/trim-blank-trace-id-space.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/trim-blank-trace-id-tab.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/trim-blank-trace-id-vt.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/trim-job-and-urn-both-blank.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/trim-reemit-job-ascii-padded.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/trim-reemit-job-unicode-padded.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/trim-reemit-trace-id-padded.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/trim-unicode-job-emsp.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/trim-unicode-job-ideographic.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/trim-unicode-job-nbsp.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/trim-urn-only-ascii-blank.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/trim-urn-only-unicode-space.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/unicode-and-numbers.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/unknown-lang.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/unknown-meta-roundtrip.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/unknown-toplevel-roundtrip.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/urn-alias.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/urn-only-roundtrip.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/fixtures/wrong-case-keys-roundtrip.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/schema/message-envelope.schema.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/conformance/schema/results.schema.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/fakes/confluent_kafka/__init__.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/fakes/confluent_kafka/admin.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/fixtures/dead-lettered.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/fixtures/order-created.json +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/redis_backend.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/test_artemis_conformance.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/test_artemis_transport.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/test_celery.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/test_codec.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/test_dead_letter.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/test_django.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/test_gdpr.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/test_headers.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/test_idempotency.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/test_kafka_conformance.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/test_kafka_integration.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/test_kafka_integration_logic.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/test_kafka_transport.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/test_otel.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/test_outbox.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/test_overhead.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/test_pika_transport.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/test_pulsar_conformance.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/test_redrive.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/test_reencode_regression.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/test_replay.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/test_schema.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/test_schema_conformance.py +0 -0
- {babelqueue-1.22.0 → babelqueue-1.24.0}/tests/test_shutdown.py +0 -0
|
@@ -177,7 +177,7 @@ jobs:
|
|
|
177
177
|
--health-retries 10
|
|
178
178
|
env:
|
|
179
179
|
# The pinned conformance release (ADR-0032). Bump together with tests/conformance/.
|
|
180
|
-
BQ_CONFORMANCE_VERSION: 1.
|
|
180
|
+
BQ_CONFORMANCE_VERSION: 1.8.0
|
|
181
181
|
# sha256 of that release's fetch.sh: the script runs on the runner, so it is pinned rather
|
|
182
182
|
# than trusted from a mutable tag. Bump together with BQ_CONFORMANCE_VERSION.
|
|
183
183
|
BQ_FETCH_SH_SHA256: 8bb6ba567b288fb0ac71a70fd17041b2503df119e01998d76fdad372570bf849
|
|
@@ -14,7 +14,7 @@ jobs:
|
|
|
14
14
|
# Recommended for PyPI Trusted Publishing — configure a "pypi" environment +
|
|
15
15
|
# a trusted publisher on PyPI (repo BabelQueue/babelqueue-python, this workflow).
|
|
16
16
|
environment: pypi
|
|
17
|
-
# redis_layout (conformance 1.
|
|
17
|
+
# redis_layout (conformance 1.7.0+) drives the real Lua scripts: a real redis:7 is mandatory,
|
|
18
18
|
# exactly as in ci.yml's `conformance` job — without it the cases are reported as failures.
|
|
19
19
|
services:
|
|
20
20
|
redis:
|
|
@@ -28,7 +28,7 @@ jobs:
|
|
|
28
28
|
--health-retries 10
|
|
29
29
|
env:
|
|
30
30
|
# The pinned conformance release (ADR-0032). Keep identical to ci.yml.
|
|
31
|
-
BQ_CONFORMANCE_VERSION: 1.
|
|
31
|
+
BQ_CONFORMANCE_VERSION: 1.8.0
|
|
32
32
|
BQ_FETCH_SH_SHA256: 8bb6ba567b288fb0ac71a70fd17041b2503df119e01998d76fdad372570bf849
|
|
33
33
|
permissions:
|
|
34
34
|
id-token: write # PyPI Trusted Publishing (OIDC) — no API token needed
|
|
@@ -9,6 +9,141 @@ The envelope wire format is versioned separately by `meta.schema_version`
|
|
|
9
9
|
|
|
10
10
|
## [Unreleased]
|
|
11
11
|
|
|
12
|
+
## [1.24.0] - 2026-10-26
|
|
13
|
+
|
|
14
|
+
Implements conformance **1.8.0** (vendored from the `v1.8.0` release asset, verified with
|
|
15
|
+
`fetch.sh --check`; `BQ_CONFORMANCE_VERSION` is now `1.8.0` in `ci.yml` and `release.yml`). The
|
|
16
|
+
envelope stays at `schema_version: 1`; nothing here touches the wire (ADR-0037). The new
|
|
17
|
+
`version_gate_pulsar`, `version_gate_artemis`, `version_gate_sqs` and `version_gate_asb` sections run
|
|
18
|
+
and pass (17 cases each; Python has the `on_unknown_urn` option, so no row is skipped). A MINOR.
|
|
19
|
+
|
|
20
|
+
### Changed (behaviour)
|
|
21
|
+
- **With the DLQ off, SQS and Azure Service Bus no longer drop a version-gated message or retry a
|
|
22
|
+
poison body; they are left to the broker's native mechanism (ADR-0037 decision 1 rule 3 and
|
|
23
|
+
decision 2 "Go and Python"; broker-bindings 3.5, 4.5, 5.7; owner decision 2026-10-25).**
|
|
24
|
+
- *Version-gated message* (an unsupported `bq-schema-version`), `dead_letter` off and a strategy
|
|
25
|
+
other than `DELETE` or `DEAD_LETTER`: it used to be acknowledged and dropped. It is now **not**
|
|
26
|
+
acknowledged. SQS: no `DeleteMessage`; visibility expiry redelivers it (the gate rejects it
|
|
27
|
+
again) and the queue's `RedrivePolicy` moves it to the native DLQ after `maxReceiveCount`. Azure
|
|
28
|
+
Service Bus: an explicit native `DeadLetter` (reason `unsupported schema version`) into
|
|
29
|
+
`$DeadLetterQueue` instead of `Complete`.
|
|
30
|
+
- *Poison body* (invalid JSON or an identity-less object), `dead_letter` off and a strategy other
|
|
31
|
+
than `DELETE` or `DEAD_LETTER`: it used to take the bounded `FAIL` path (re-publish an empty
|
|
32
|
+
envelope up to `max_attempts`, then drop). On SQS and Azure Service Bus it is now settled
|
|
33
|
+
natively **on the first delivery** exactly as above (Azure Service Bus reason `poison`): no
|
|
34
|
+
re-publish, no retry, no ack, body unchanged, the event is logged. Every other transport
|
|
35
|
+
(Pulsar, Artemis, AMQP, Kafka, Redis, memory) keeps its behaviour; `DELETE` (ack and drop),
|
|
36
|
+
`dead_letter=True` and the `DEAD_LETTER` strategy (the raw record, then ack) are unchanged on
|
|
37
|
+
SQS and Azure Service Bus too.
|
|
38
|
+
- A deployment that relied on SQS/Azure Service Bus silently dropping these messages now needs a
|
|
39
|
+
`RedrivePolicy` (SQS) or accepts them in `$DeadLetterQueue` (Azure Service Bus), or sets
|
|
40
|
+
`dead_letter=True` / `on_unknown_urn=DELETE`.
|
|
41
|
+
|
|
42
|
+
### Fixed
|
|
43
|
+
- **SQS: the default dead-letter queue name is now `<queue>-dlq` (FIFO `<queue>-dlq.fifo`) (ADR-0037
|
|
44
|
+
decision 7).** The old default `<queue>.dlq` was never a valid Amazon SQS queue name (a name may hold only
|
|
45
|
+
alphanumerics, hyphens and underscores, plus one `.fifo` suffix), so a DLQ write by default could not find a
|
|
46
|
+
queue on real SQS. `dead_letter_suffix` now defaults to `None` ("not set"); unless `dead_letter_queue` is set
|
|
47
|
+
the runtime asks the transport's new optional `DeadLetterNamer` capability
|
|
48
|
+
(`dead_letter_queue_name(queue, suffix)`, exported from `babelqueue`), which `SqsTransport` implements. The
|
|
49
|
+
runtime also hands it an explicit `dead_letter_suffix`; on a FIFO queue the `.fifo` suffix always stays last,
|
|
50
|
+
an explicit suffix included: `orders.fifo` with `dead_letter_suffix="-x"` is `orders-x.fifo`, never
|
|
51
|
+
`orders.fifo-x` (an SQS FIFO name must end in `.fifo`; before, that explicit suffix produced the uncreatable
|
|
52
|
+
`orders.fifo-x`). An explicit queue name behaves as before; every other transport keeps `<queue>.dlq` (the
|
|
53
|
+
attribute `App.dead_letter_suffix` is `None` instead of `".dlq"` until set). Deployments
|
|
54
|
+
that relied on the SQS default must name the DLQ `<queue>-dlq`, or pass `dead_letter_suffix=".dlq"` /
|
|
55
|
+
`dead_letter_queue=` to keep the old name. An explicitly empty `dead_letter_suffix=""` now counts as "no suffix" on SQS (`-dlq`); before, it made the DLQ the source queue itself.
|
|
56
|
+
|
|
57
|
+
### Added
|
|
58
|
+
- **`babelqueue.transport.NativeSettler`**, an optional `Transport` capability
|
|
59
|
+
(`settle_native(message, reason, description)`). With the DLQ off the runtime calls it instead of
|
|
60
|
+
acknowledging a version-gated message (and, on the poison route, instead of the bounded retry) on
|
|
61
|
+
a transport that offers it; the decision follows the capability, never the transport's name.
|
|
62
|
+
`SqsTransport.settle_native` is a deliberate no-op on the wire; `AsbTransport.settle_native`
|
|
63
|
+
dead-letters natively (falling back to `abandon_message` for a receiver without
|
|
64
|
+
`dead_letter_message`). Transports without it are unchanged.
|
|
65
|
+
- **`babelqueue.transport.Abandoner` and `AsbTransport.abandon`.** When the dead-letter write of a
|
|
66
|
+
*version-gated* message fails, Azure Service Bus now `Abandon`s the peek-lock (broker-bindings 4.5,
|
|
67
|
+
"A failed write `Abandon`s it") so the broker redelivers it at once, instead of leaving it locked until
|
|
68
|
+
the lock lapses (up to 5 minutes). Only that branch abandons (owner decision 2026-10-25): `AsbTransport`
|
|
69
|
+
is deliberately **not** a `Rewinder`, so a graceful-shutdown release and a failed retry re-publish keep
|
|
70
|
+
their previous handling (a copy is re-published and the original completed), and a failed dead-letter
|
|
71
|
+
write of a poison body is still left to its lock. Tests pin all three. The `version_gate_asb` runner
|
|
72
|
+
asserts the `Abandon` on its `unsettled` rows.
|
|
73
|
+
- Conformance `version_gate_*` runners (`version_gate_pulsar` / `version_gate_artemis` through the
|
|
74
|
+
runtime, `version_gate_sqs` / `version_gate_asb` through the real transports) and their entries in
|
|
75
|
+
the results writer.
|
|
76
|
+
|
|
77
|
+
## [1.23.0] - 2026-10-25
|
|
78
|
+
|
|
79
|
+
Implements ADR-0036 (post-R1 parity) decisions 2, 4, 5 and 6. A MINOR: every change is a
|
|
80
|
+
consumer-side settle decision, so the envelope stays at `schema_version: 1`. The vendored
|
|
81
|
+
conformance suite moves to v1.7.0 (new sections `identity_verdict` and `pulsar_exhaustion`, both
|
|
82
|
+
passing; `conformance-known-gaps.json` stays empty).
|
|
83
|
+
|
|
84
|
+
### Changed (behaviour)
|
|
85
|
+
- **A body that does not decode, or has no identity, is poison on every transport (ADR-0036
|
|
86
|
+
decisions 4 and 6).** A JSON object that has neither a valid string `job` nor a valid string
|
|
87
|
+
`urn` (ADR-0032 section 6) used to be an *unknown URN*, and on SQS, AMQP, Pulsar, Azure Service
|
|
88
|
+
Bus, Artemis and the memory transport a body that did not decode was decoded leniently into an
|
|
89
|
+
empty envelope and retried as an unknown URN, finally dead-lettered as `reason: "unknown_urn"`
|
|
90
|
+
without the original body. Both are now **poison** and take the poison route of Go's
|
|
91
|
+
`routePoison`: they are never handed to a handler and never take the unknown-URN strategies
|
|
92
|
+
(those remain for a valid envelope whose URN has no handler). With the DLQ on (`dead_letter=True`
|
|
93
|
+
or `on_unknown_urn=DEAD_LETTER`) the message is written to the DLQ at once, with no retry, as the
|
|
94
|
+
ADR-0035 record (`dead_letter.reason: "poison"`, the original body preserved: a strict JSON
|
|
95
|
+
object spliced byte for byte, anything else as `raw`, base64 plus `raw_encoding` when it is not
|
|
96
|
+
valid UTF-8) and acknowledged after the write; `on_unknown_urn=DELETE` drops it (logged); with
|
|
97
|
+
the DLQ off `RELEASE` is replaced by the bounded `FAIL` path (re-published with `attempts + 1`
|
|
98
|
+
up to `max_attempts`, then dropped and logged). An operator who relied on a poison body being
|
|
99
|
+
retried through the unknown-URN strategy, or on a `reason: "unknown_urn"` record for it, sees the
|
|
100
|
+
new behaviour. The classification is `EnvelopeCodec.poison_cause(raw)` (new, pure): the typed
|
|
101
|
+
decode of the Go reference plus the identity rule; `decode` / `decode_lenient` are unchanged.
|
|
102
|
+
- **Pulsar poison records carry `reason: "poison"`** (they were `unknown_urn`). The Pulsar
|
|
103
|
+
transport also reports the reconciled `bq-attempts` / redelivery count to the runtime
|
|
104
|
+
(`ReceivedMessage.native_attempts`, new), as does SQS (`ApproximateReceiveCount - 1`), so a poison
|
|
105
|
+
body, which cannot carry `attempts`, is still bounded by `max_attempts`.
|
|
106
|
+
- **Redis: an identity-less body is dead-lettered unconditionally (ADR-0036 decision 4,
|
|
107
|
+
broker-bindings section 1.1 "Identity-less body").** In both layouts (legacy `:processing`
|
|
108
|
+
and Laravel-compatible zset) a body that decodes but names no identity (including a bare `null`,
|
|
109
|
+
which used to follow the bounded `FAIL` path) is handed over as transport poison: it is written
|
|
110
|
+
to `<queue>.dlq` as the ADR-0035 record with `reason: "poison"` in every configuration
|
|
111
|
+
(`on_unknown_urn=DELETE` and dead-lettering off change nothing), never handed to a handler and
|
|
112
|
+
never retried. Nothing else in the Redis transport changes.
|
|
113
|
+
- **Kafka without retry tiers: a poison record no longer blocks the partition (ADR-0036 decision
|
|
114
|
+
5, broker-bindings section 6.5 degrade-to-delete).** With no `retry_tiers_ms`, dead-lettering off
|
|
115
|
+
and `on_unknown_urn` not `DELETE`, the bounded retry of a poison record (including an
|
|
116
|
+
identity-less body) needs a tier and raised, leaving the record uncommitted with `bq-attempts`
|
|
117
|
+
never advancing. It is now committed, dropped and logged, and the partition advances. A failing
|
|
118
|
+
handler and `RELEASE` of a valid envelope keep the section 6.5 rule (they still raise
|
|
119
|
+
`BabelQueueError` without tiers). The start-up warning for a tierless transport now says so; enable
|
|
120
|
+
`dead_letter` to keep such records in `<topic>.dlq`.
|
|
121
|
+
- A message dropped after its retries are exhausted with no DLQ configured is now logged
|
|
122
|
+
(`babelqueue.app`, WARNING) instead of being dropped silently.
|
|
123
|
+
|
|
124
|
+
- **Pulsar: a failed DLQ write or retry publish is negatively acknowledged (Go `Rewind`).**
|
|
125
|
+
`PulsarTransport` is now a `Rewinder` (`negative_acknowledge`), so the unsettled original is
|
|
126
|
+
redelivered by the broker instead of staying un-acknowledged for the life of the consumer. A
|
|
127
|
+
graceful-shutdown release of an in-flight Pulsar message is now a nack as well rather than a
|
|
128
|
+
re-publish (on a `Shared` subscription the native redelivery count advances; on `Exclusive` /
|
|
129
|
+
`Failover` it does not, which is harmless: `bq-attempts` carries the attempt limit).
|
|
130
|
+
|
|
131
|
+
### Fixed
|
|
132
|
+
- **Bytes that are not valid UTF-8 no longer crash the AMQP, Pulsar and Artemis consumers.** They
|
|
133
|
+
were decoded strictly in `pop`; they are now kept losslessly (`surrogateescape`). Invalid UTF-8
|
|
134
|
+
is poison wherever it sits, **also inside a JSON string** (`EnvelopeCodec.poison_cause`,
|
|
135
|
+
error-handling section 7): it is never handed to a handler and is dead-lettered as the ADR-0035
|
|
136
|
+
base64 record, like on Redis and Kafka.
|
|
137
|
+
|
|
138
|
+
### Added
|
|
139
|
+
- `EnvelopeCodec.poison_cause(raw, *, require_identity=True)`; `Transport.classifies_poison`
|
|
140
|
+
(Kafka and Redis classify poison themselves and opt out of the runtime's classification);
|
|
141
|
+
`ReceivedMessage.native_attempts`.
|
|
142
|
+
- Conformance runners for `identity_verdict` (the core verdict on all 97 bodies, plus the fate on
|
|
143
|
+
the memory transport) and `pulsar_exhaustion` (all 29 rows, driven through the real
|
|
144
|
+
`PulsarTransport` and runtime over a duck-typed client), and per-transport poison tests.
|
|
145
|
+
- `ci.yml` / `release.yml` pin conformance `1.7.0` (the `fetch.sh` SHA-256 is unchanged).
|
|
146
|
+
|
|
12
147
|
## [1.22.0] - 2026-10-24
|
|
13
148
|
|
|
14
149
|
Implements ADR-0033 (Redis) and ADR-0034 (Kafka tiers, backoff, poison). The envelope stays at
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: babelqueue
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.24.0
|
|
4
4
|
Summary: Polyglot Queues, Simplified — the Python core: the canonical BabelQueue wire-envelope codec, contracts and dead-letter helpers.
|
|
5
5
|
Project-URL: Homepage, https://babelqueue.com
|
|
6
6
|
Project-URL: Source, https://github.com/BabelQueue/babelqueue-python
|
|
@@ -212,8 +212,13 @@ untrimmed; Azure Service Bus and Artemis also accept the integer `1`). A message
|
|
|
212
212
|
anything else is not decoded: it reaches the runtime on the reserved route
|
|
213
213
|
`babelqueue:unsupported-schema-version:<v>` (the version percent-escaped) and is **never
|
|
214
214
|
retried** — it goes straight to the dead-letter queue (the incoming body, byte-identical,
|
|
215
|
-
with no `dead_letter` block) when `dead_letter` is enabled
|
|
216
|
-
|
|
215
|
+
with no `dead_letter` block) when `dead_letter` is enabled (or `on_unknown_urn=DEAD_LETTER`), and
|
|
216
|
+
`on_unknown_urn=DELETE` drops it, whatever `max_attempts` is. With `dead_letter` off, **SQS and Azure
|
|
217
|
+
Service Bus no longer drop it** (ADR-0037): it is left to the broker's native mechanism and logged
|
|
218
|
+
(SQS: no `DeleteMessage`, so visibility expiry redelivers it — the gate rejects it again — and the
|
|
219
|
+
queue's `RedrivePolicy` moves it to the native DLQ after `maxReceiveCount`; Azure Service Bus: an
|
|
220
|
+
explicit native `DeadLetter` with reason `unsupported schema version` into `$DeadLetterQueue`
|
|
221
|
+
instead of `Complete`). Kafka, Artemis and Pulsar still acknowledge and drop it. If the dead-letter write fails the message is
|
|
217
222
|
left unacknowledged (an error is logged), is never retried and never reaches a handler; the
|
|
218
223
|
dead-letter write is attempted again when the broker brings it back, which depends on the
|
|
219
224
|
broker:
|
|
@@ -253,10 +258,17 @@ a warning. A **per-message delay** at publish time is
|
|
|
253
258
|
standard queue; a larger value, or any per-message delay on a FIFO queue, raises
|
|
254
259
|
`BabelQueueError` instead of being truncated or dropped).
|
|
255
260
|
|
|
261
|
+
**Poison bodies.** A body that does not decode, or has no identity, is never retried by the SDK
|
|
262
|
+
(ADR-0037): `dead_letter=True` writes the ADR-0035 record to the DLQ (`<queue>-dlq` on SQS, `<queue>.dlq` elsewhere) and then deletes it,
|
|
263
|
+
`on_unknown_urn=DELETE` deletes it, and with the DLQ off it is **not deleted and not re-sent**: the
|
|
264
|
+
transport's `settle_native` capability leaves it to SQS on the first delivery (visibility expiry,
|
|
265
|
+
then the queue's `RedrivePolicy`; the event is logged). Azure Service Bus does the same with a native
|
|
266
|
+
`DeadLetter` (reason `poison`). Every other transport keeps the bounded retry up to `max_attempts`.
|
|
267
|
+
|
|
256
268
|
**Poison-loop risk:** a message that always fails is redelivered at once until
|
|
257
269
|
`max_attempts` is reached. If the receive count is unavailable the SDK cannot
|
|
258
270
|
advance attempts at all. **Configure a native `RedrivePolicy`**
|
|
259
|
-
(`maxReceiveCount` ≥ `max_attempts`, pointing at `<queue
|
|
271
|
+
(`maxReceiveCount` ≥ `max_attempts`, pointing at `<queue>-dlq`, the SQS default DLQ name: FIFO `<queue>-dlq.fifo`, because an SQS queue name cannot contain a dot; `dead_letter_queue` overrides it, and `dead_letter_suffix` replaces `-dlq`, placed before `.fifo` on a FIFO queue) on every SQS
|
|
260
272
|
queue as the broker-side backstop, and set a non-zero `retry_backoff` if the
|
|
261
273
|
handler's dependencies need time to recover.
|
|
262
274
|
|
|
@@ -313,9 +325,31 @@ the DLQ on (`dead_letter` or `on_unknown_urn=DEAD_LETTER`) it is dead-lettered o
|
|
|
313
325
|
written to `<topic>.dlq` (which must exist) and its offset is committed once that write
|
|
314
326
|
is confirmed; a failed write leaves it uncommitted and rewound. With the DLQ off nothing is written:
|
|
315
327
|
`on_unknown_urn=DELETE` drops it, any other strategy retries it through the retry tiers up to
|
|
316
|
-
`max_attempts` and then drops it
|
|
317
|
-
the
|
|
318
|
-
|
|
328
|
+
`max_attempts` and then drops it. **Without retry tiers** that bounded retry has no tier to use, so
|
|
329
|
+
(with the DLQ off and `on_unknown_urn` not `DELETE`) the poison record is committed, dropped and logged
|
|
330
|
+
instead of blocking the partition (section 6.5 degrade-to-delete, ADR-0036 decision 5); enable
|
|
331
|
+
`dead_letter` to keep it in `<topic>.dlq`. A failing handler without tiers still cannot be retried, as above.
|
|
332
|
+
|
|
333
|
+
### Poison messages on every other transport
|
|
334
|
+
|
|
335
|
+
A message body that does not decode into an envelope (not a JSON object, malformed, a wrongly typed
|
|
336
|
+
member, or bytes that are not valid UTF-8, even inside a JSON string) or that has neither a valid
|
|
337
|
+
string `job` nor a valid string `urn` is **poison** on every transport (ADR-0036 decisions 2, 4 and
|
|
338
|
+
6; conformance `identity_verdict`). It is never handed to a handler and never takes the
|
|
339
|
+
unknown-URN strategies, which are for a valid envelope whose URN has no handler:
|
|
340
|
+
|
|
341
|
+
- DLQ on (`dead_letter` or `on_unknown_urn=DEAD_LETTER`): written to `<queue>.dlq` at once, with no
|
|
342
|
+
retry, as the ADR-0035 record (`dead_letter.reason: "poison"`, the original body preserved,
|
|
343
|
+
base64 plus `raw_encoding` when it is not UTF-8), then acknowledged. A failed write leaves it
|
|
344
|
+
unacknowledged.
|
|
345
|
+
- `on_unknown_urn=DELETE`: acknowledged and dropped (logged).
|
|
346
|
+
- DLQ off: the bounded `FAIL` path (`RELEASE` is replaced by it): retried up to `max_attempts`, then
|
|
347
|
+
dropped and logged. The count comes from the broker where it has one (SQS receive count, Pulsar
|
|
348
|
+
`bq-attempts` / redelivery count), otherwise from a bare `{"attempts": n}` body the retry leaves.
|
|
349
|
+
|
|
350
|
+
On Redis (both layouts) an identity-less body is dead-lettered as poison in **every** configuration,
|
|
351
|
+
including `on_unknown_urn=DELETE` and dead-lettering off (broker-bindings section 1.1). On the legacy
|
|
352
|
+
(`<queue>:processing`) layout a body that Go's typed decode rejects is dead-lettered raw on its first
|
|
319
353
|
delivery and removed from `:processing`.
|
|
320
354
|
|
|
321
355
|
### Sharing a Redis queue with Laravel
|
|
@@ -158,8 +158,13 @@ untrimmed; Azure Service Bus and Artemis also accept the integer `1`). A message
|
|
|
158
158
|
anything else is not decoded: it reaches the runtime on the reserved route
|
|
159
159
|
`babelqueue:unsupported-schema-version:<v>` (the version percent-escaped) and is **never
|
|
160
160
|
retried** — it goes straight to the dead-letter queue (the incoming body, byte-identical,
|
|
161
|
-
with no `dead_letter` block) when `dead_letter` is enabled
|
|
162
|
-
|
|
161
|
+
with no `dead_letter` block) when `dead_letter` is enabled (or `on_unknown_urn=DEAD_LETTER`), and
|
|
162
|
+
`on_unknown_urn=DELETE` drops it, whatever `max_attempts` is. With `dead_letter` off, **SQS and Azure
|
|
163
|
+
Service Bus no longer drop it** (ADR-0037): it is left to the broker's native mechanism and logged
|
|
164
|
+
(SQS: no `DeleteMessage`, so visibility expiry redelivers it — the gate rejects it again — and the
|
|
165
|
+
queue's `RedrivePolicy` moves it to the native DLQ after `maxReceiveCount`; Azure Service Bus: an
|
|
166
|
+
explicit native `DeadLetter` with reason `unsupported schema version` into `$DeadLetterQueue`
|
|
167
|
+
instead of `Complete`). Kafka, Artemis and Pulsar still acknowledge and drop it. If the dead-letter write fails the message is
|
|
163
168
|
left unacknowledged (an error is logged), is never retried and never reaches a handler; the
|
|
164
169
|
dead-letter write is attempted again when the broker brings it back, which depends on the
|
|
165
170
|
broker:
|
|
@@ -199,10 +204,17 @@ a warning. A **per-message delay** at publish time is
|
|
|
199
204
|
standard queue; a larger value, or any per-message delay on a FIFO queue, raises
|
|
200
205
|
`BabelQueueError` instead of being truncated or dropped).
|
|
201
206
|
|
|
207
|
+
**Poison bodies.** A body that does not decode, or has no identity, is never retried by the SDK
|
|
208
|
+
(ADR-0037): `dead_letter=True` writes the ADR-0035 record to the DLQ (`<queue>-dlq` on SQS, `<queue>.dlq` elsewhere) and then deletes it,
|
|
209
|
+
`on_unknown_urn=DELETE` deletes it, and with the DLQ off it is **not deleted and not re-sent**: the
|
|
210
|
+
transport's `settle_native` capability leaves it to SQS on the first delivery (visibility expiry,
|
|
211
|
+
then the queue's `RedrivePolicy`; the event is logged). Azure Service Bus does the same with a native
|
|
212
|
+
`DeadLetter` (reason `poison`). Every other transport keeps the bounded retry up to `max_attempts`.
|
|
213
|
+
|
|
202
214
|
**Poison-loop risk:** a message that always fails is redelivered at once until
|
|
203
215
|
`max_attempts` is reached. If the receive count is unavailable the SDK cannot
|
|
204
216
|
advance attempts at all. **Configure a native `RedrivePolicy`**
|
|
205
|
-
(`maxReceiveCount` ≥ `max_attempts`, pointing at `<queue
|
|
217
|
+
(`maxReceiveCount` ≥ `max_attempts`, pointing at `<queue>-dlq`, the SQS default DLQ name: FIFO `<queue>-dlq.fifo`, because an SQS queue name cannot contain a dot; `dead_letter_queue` overrides it, and `dead_letter_suffix` replaces `-dlq`, placed before `.fifo` on a FIFO queue) on every SQS
|
|
206
218
|
queue as the broker-side backstop, and set a non-zero `retry_backoff` if the
|
|
207
219
|
handler's dependencies need time to recover.
|
|
208
220
|
|
|
@@ -259,9 +271,31 @@ the DLQ on (`dead_letter` or `on_unknown_urn=DEAD_LETTER`) it is dead-lettered o
|
|
|
259
271
|
written to `<topic>.dlq` (which must exist) and its offset is committed once that write
|
|
260
272
|
is confirmed; a failed write leaves it uncommitted and rewound. With the DLQ off nothing is written:
|
|
261
273
|
`on_unknown_urn=DELETE` drops it, any other strategy retries it through the retry tiers up to
|
|
262
|
-
`max_attempts` and then drops it
|
|
263
|
-
the
|
|
264
|
-
|
|
274
|
+
`max_attempts` and then drops it. **Without retry tiers** that bounded retry has no tier to use, so
|
|
275
|
+
(with the DLQ off and `on_unknown_urn` not `DELETE`) the poison record is committed, dropped and logged
|
|
276
|
+
instead of blocking the partition (section 6.5 degrade-to-delete, ADR-0036 decision 5); enable
|
|
277
|
+
`dead_letter` to keep it in `<topic>.dlq`. A failing handler without tiers still cannot be retried, as above.
|
|
278
|
+
|
|
279
|
+
### Poison messages on every other transport
|
|
280
|
+
|
|
281
|
+
A message body that does not decode into an envelope (not a JSON object, malformed, a wrongly typed
|
|
282
|
+
member, or bytes that are not valid UTF-8, even inside a JSON string) or that has neither a valid
|
|
283
|
+
string `job` nor a valid string `urn` is **poison** on every transport (ADR-0036 decisions 2, 4 and
|
|
284
|
+
6; conformance `identity_verdict`). It is never handed to a handler and never takes the
|
|
285
|
+
unknown-URN strategies, which are for a valid envelope whose URN has no handler:
|
|
286
|
+
|
|
287
|
+
- DLQ on (`dead_letter` or `on_unknown_urn=DEAD_LETTER`): written to `<queue>.dlq` at once, with no
|
|
288
|
+
retry, as the ADR-0035 record (`dead_letter.reason: "poison"`, the original body preserved,
|
|
289
|
+
base64 plus `raw_encoding` when it is not UTF-8), then acknowledged. A failed write leaves it
|
|
290
|
+
unacknowledged.
|
|
291
|
+
- `on_unknown_urn=DELETE`: acknowledged and dropped (logged).
|
|
292
|
+
- DLQ off: the bounded `FAIL` path (`RELEASE` is replaced by it): retried up to `max_attempts`, then
|
|
293
|
+
dropped and logged. The count comes from the broker where it has one (SQS receive count, Pulsar
|
|
294
|
+
`bq-attempts` / redelivery count), otherwise from a bare `{"attempts": n}` body the retry leaves.
|
|
295
|
+
|
|
296
|
+
On Redis (both layouts) an identity-less body is dead-lettered as poison in **every** configuration,
|
|
297
|
+
including `on_unknown_urn=DELETE` and dead-lettering off (broker-bindings section 1.1). On the legacy
|
|
298
|
+
(`<queue>:processing`) layout a body that Go's typed decode rejects is dead-lettered raw on its first
|
|
265
299
|
delivery and removed from `:processing`.
|
|
266
300
|
|
|
267
301
|
### Sharing a Redis queue with Laravel
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "babelqueue"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.24.0"
|
|
8
8
|
description = "Polyglot Queues, Simplified — the Python core: the canonical BabelQueue wire-envelope codec, contracts and dead-letter helpers."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -30,10 +30,13 @@ from .exceptions import BabelQueueError, DecryptError, UnknownUrnError
|
|
|
30
30
|
from .replay import HEADER_REPLAY_BYPASS, bypass_external_effects, is_replay
|
|
31
31
|
from .routing import UnknownUrnStrategy
|
|
32
32
|
from .transport import (
|
|
33
|
+
Abandoner,
|
|
33
34
|
BatchPopper,
|
|
35
|
+
DeadLetterNamer,
|
|
34
36
|
DeadLetterWriter,
|
|
35
37
|
HeaderPublisher,
|
|
36
38
|
InMemoryTransport,
|
|
39
|
+
NativeSettler,
|
|
37
40
|
ReceivedMessage,
|
|
38
41
|
Redeliverer,
|
|
39
42
|
Rewinder,
|
|
@@ -42,7 +45,7 @@ from .transport import (
|
|
|
42
45
|
Transport,
|
|
43
46
|
)
|
|
44
47
|
|
|
45
|
-
__version__ = "1.
|
|
48
|
+
__version__ = "1.24.0"
|
|
46
49
|
|
|
47
50
|
__all__ = [
|
|
48
51
|
"BabelQueue",
|
|
@@ -55,9 +58,12 @@ __all__ = [
|
|
|
55
58
|
"Transport",
|
|
56
59
|
"InMemoryTransport",
|
|
57
60
|
"ReceivedMessage",
|
|
61
|
+
"Abandoner",
|
|
58
62
|
"BatchPopper",
|
|
63
|
+
"DeadLetterNamer",
|
|
59
64
|
"DeadLetterWriter",
|
|
60
65
|
"HeaderPublisher",
|
|
66
|
+
"NativeSettler",
|
|
61
67
|
"Redeliverer",
|
|
62
68
|
"Rewinder",
|
|
63
69
|
"RoutedPublisher",
|
|
@@ -15,7 +15,7 @@ Go reference's ``babelqueue.Decode``, except that member names are case-sensitiv
|
|
|
15
15
|
decoder read them) and every occurrence of a duplicated key is checked; any other member (a
|
|
16
16
|
differently-cased name or a non-string ``urn`` alias included) is only checked for syntax.
|
|
17
17
|
A non-string ``job`` is **not** poison either: the identity resolver ignores it (ADR-0032 section 6),
|
|
18
|
-
so the body is readable and simply carries no identity (conformance ``kafka_poison``, v1.6.0).
|
|
18
|
+
so the body is readable and simply carries no identity (conformance ``kafka_poison``, v1.6.0, and ``identity_verdict``, v1.7.0).
|
|
19
19
|
|
|
20
20
|
A well-typed but non-conformant envelope is not poison: Go's consume path never calls ``Accepts``.
|
|
21
21
|
"""
|