Skip to content

fix(confluent): publish(None) should send a real Kafka tombstone#2932

Merged
Lancetnik merged 3 commits into
ag2ai:mainfrom
aradng:fix/confluent-tombstone
Jul 13, 2026
Merged

fix(confluent): publish(None) should send a real Kafka tombstone#2932
Lancetnik merged 3 commits into
ag2ai:mainfrom
aradng:fix/confluent-tombstone

Conversation

@aradng

@aradng aradng commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

publish(None, ...) doesn't actually produce a Kafka tombstone right now - encode_message() turns None into b"" before it reaches the producer. For a compacted topic that means log compaction never reclaims the key: an empty-but-present value just stays forever, only a literal null does the job.

This skips the codec when the body is None and lets the raw producer send an actual null value instead.

Added a test that reproduces it (fails on main with assert b'' is None, passes with the fix).

@aradng aradng requested a review from Lancetnik as a code owner July 13, 2026 13:01
@CLAassistant

CLAassistant commented Jul 13, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@github-actions github-actions Bot added the Confluent Issues related to `faststream.confluent` module label Jul 13, 2026
encode_message() turns None into b, so a delete on a compacted topic
never actually reaches the broker as a null value. Compaction only
reclaims a key on a literal null - an empty-but-present payload just
sits there forever. Skip the codec when the body is None so the raw
producer gets what it needs to do this properly.
@aradng aradng force-pushed the fix/confluent-tombstone branch from a1976c2 to 19df9ef Compare July 13, 2026 13:04
Mirror the confluent fix in the aiokafka producer. Unlike confluent,
aiokafka rejects records with neither key nor value, and publish(None)
without a key is valid API usage (covered by test_publisher_after_connect),
so only keyed None bodies bypass the codec and become tombstones.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions github-actions Bot added the AioKafka Issues related to `faststream.kafka` module label Jul 13, 2026
uvicorn 0.51 removed the `target` argument from Multiprocess and
Process — Process now builds its own Server from the config. Detect
the new signature at import time and construct both objects
accordingly, keeping compatibility with uvicorn>=0.34.3.

This unbreaks main CI (tests/cli asgi multi-worker tests fail on every
run since uvicorn 0.51 released) and the reported CLI crash
`TypeError: Multiprocess.__init__() got an unexpected keyword argument 'target'`.

Fixes ag2ai#2930

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Lancetnik Lancetnik enabled auto-merge July 13, 2026 15:45
@Lancetnik Lancetnik added this pull request to the merge queue Jul 13, 2026
Merged via the queue into ag2ai:main with commit 5b98b87 Jul 13, 2026
29 checks passed
aradng added a commit to aradng/FastLoom that referenced this pull request Jul 13, 2026
Tracking main means the resolved commit silently drifts on every
poetry lock, and this is production infra - reproducible builds matter
more than always-latest. Pin to 9d54a6d8, the commit that includes
ag2ai/faststream#2932, and re-lock explicitly when it's time to move
(e.g. once #2933 merges too).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
aradng added a commit to aradng/FastLoom that referenced this pull request Jul 13, 2026
* fix: depend on faststream's git main for the real tombstone fix

ag2ai/faststream#2932 (the actual upstream fix for publish(None, ...)
not sending a real Kafka null value) is merged to main but not yet in a
PyPI release. Point the kafka extra at git+https://github.com/ag2ai/
faststream.git@main instead of waiting, and drop the runtime monkeypatch
in depends.py entirely - the real fix now lives upstream, so there's
nothing left to patch.

Bumps to 0.4.49.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix: pin faststream to an exact commit instead of tracking main

Tracking main means the resolved commit silently drifts on every
poetry lock, and this is production infra - reproducible builds matter
more than always-latest. Pin to 9d54a6d8, the commit that includes
ag2ai/faststream#2932, and re-lock explicitly when it's time to move
(e.g. once #2933 merges too).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
aradng added a commit to aradng/FastLoom that referenced this pull request Jul 13, 2026
… refs (#18)

0.4.49's publish failed: PyPI's upload validation hard-rejects any package
declaring a direct git/URL dependency (HTTP 400 "Can't have direct
dependency"). That's not a config issue - it's a policy PyPI enforces on
every upload, so pointing the kafka extra at faststream's git main broke
the publish step for good, not just this one release.

Revert to a plain "faststream[otel,confluent]" PyPI dependency and
restore the AsyncConfluentFastProducerImpl.publish() monkeypatch from
0.4.48. ag2ai/faststream#2932 is merged upstream but has no PyPI release
yet, so the shim stays until one exists.

Bumps to 0.4.50 (0.4.49 never actually published - the tarball was
rejected before completing).

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AioKafka Issues related to `faststream.kafka` module Confluent Issues related to `faststream.confluent` module

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: FastStream CLI with ASGI and multiple workers breaks on Uvicorn 0.51

3 participants