fix: align kafka consumer fetch ceiling to 64 MiB broker max#442
Conversation
librdkafka defaults max.partition.fetch.bytes to 1 MiB and fetch.max.bytes to 50 MiB, both below the 64 MiB a DLQ re-publish can reach. An oversized-but-valid record is accepted/stored by the broker yet trips MSG_SIZE_TOO_LARGE on consume, wedging the partition in a re-seek loop (observed: DLQ replay group at ~243 MiB in-flight, 0 committed partitions). Raise consumer fetch ceilings to match the producer/broker 64 MiB max.message.bytes. Config-only; applies to both primary and _dlq groups.
|
test |
|
---## Code Review### Overview |
Code ReviewOverviewConfig-only fix that raises the consumer-side librdkafka fetch ceilings to match the 64 MiB The fix is correct ✓
These exactly mirror the producer settings already on lines 118–119, which is the right invariant to enforce. Suggestions1. Over-verbose block comment (succinctness) The 5-line comment block (lines 473–477) mostly reproduces the PR description. The existing file style uses terse inline comments (see <> K.extraProp "max.partition.fetch.bytes" "67108864" -- 64 MiB, matches broker max.message.bytes
<> K.extraProp "fetch.max.bytes" "67108864" -- 64 MiB total per fetch
<> K.extraProp "receive.message.max.bytes" "104857600" -- 100 MiB socket buffer (headroom over fetch.max.bytes)2. Duplicated magic numbers
kafkaMaxMessageBytes, kafkaReceiveBufferBytes :: String
kafkaMaxMessageBytes = "67108864" -- 64 MiB
kafkaReceiveBufferBytes = "104857600" -- 100 MiB3. Minor: Setting them equal means a single 64 MiB message saturates the entire fetch response, blocking simultaneous fetches from other assigned partitions. Likely intentional for the DLQ case, but worth a note if this consumer group handles many partitions. SummaryThe fix is correct and addresses an observed production issue. The main feedback is style: the block comment is verbose relative to the rest of the file, and the duplicated magic-number strings are now a three-way sync point. Neither is a blocker. |
|
(Deleting test comments — this is the real review below.) |
Code ReviewOverviewTwo independent changes: (1) a config-only fix raising Kafka consumer fetch ceilings to match the 64 MiB broker
|
| Verdict | |
|---|---|
| Fix correctness | ✅ |
| Producer/consumer value parity | ✅ |
| Magic number duplication | Minor — worth a constants extraction |
| Comment verbosity (Queue.hs) | Minor — trim to 2 lines |
Control.Exception choice in test |
✅ intentional |
| Date/bug-ref comment in test | Nit — belongs in commit message, not code |
| Test coverage | Adequate for the new function; Kafka config untestable without integration environment |
Code ReviewOverviewA targeted, well-motivated fix for a real production incident. The DLQ replay group wedging is clearly explained and the config values are consistent with librdkafka constraints. The test file additions are separate unrelated work (new regression tests for
|
| Config fix | ✅ Correct. Values match librdkafka constraints; ordering relative to other props is fine. |
| Magic numbers | |
Control.Exception |
UnliftIO.Exception. |
| Tests | ✅ Good regression coverage for cancelAllConcurrently; assertions are meaningful. |
The fix itself is sound and should be landed promptly per the deploy sequencing in the PR description. The style items above are low-risk but worth cleaning up in a follow-up or before merge.
What
Raise consumer-side fetch ceilings in
consumerProps(src/Pkg/Queue.hs) to match the producer/broker 64 MiBmax.message.bytes:max.partition.fetch.bytesfetch.max.bytesreceive.message.max.bytesApplies to both the primary ingest group and the
_dlqreplay group.Why
librdkafka defaults
max.partition.fetch.bytesto 1 MiB andfetch.max.bytesto 50 MiB — both below the 64 MiB a DLQ re-publish can reach. An oversized-but-valid record (esp. header-restamped DLQ messages) is accepted and stored by the broker, yet tripsMSG_SIZE_TOO_LARGEon consume, wedging the partition in a re-seek loop.Observed live: DLQ replay group
mono-dlq-46b7bcholding ~243 MiB in-flight with 0 committed partitions.Risk
Config-only.
receive.message.max.bytes(100 MiB) ≥fetch.max.bytes(64 MiB) + overhead, so librdkafka accepts the config.fetch.max.bytescaps total in-flight per fetch regardless of partition count.Deploy sequencing
Land this first, confirm the DLQ group starts committing (
committed_partitions> 0,inflight_bytesdropping), then consider any DLQ prune. This fixes oversized-but-valid records only — genuine poison (wire-type 6/7, truncated protobuf) still needs the manual prune path.