Repository navigation
feat: allow configuring any kafka consumer or producer property - #117
Conversation
|
CI confirms the build blocker described above — the Run 30901027620. This is Repairing that build is a separate change (the |
The dead letter producer has no way to set max.request.size, so a record above the 1 MiB default cannot be dead-lettered at all - the produce fails, Monitor.produceError fires, and the offset is never acknowledged. Adds KAFKA_CONSUMER_PROPERTY_* and KAFKA_PRODUCER_PROPERTY_* passthroughs, mirroring osskit/dafka-producer#38. Two prefixes rather than one because the consumer and the dead letter producer are separate clients with disjoint property sets. Dedicated parameters still win over the passthrough. Co-authored-by: Cursor <cursoragent@cursor.com>
efd4bf7 to
42ca9f0
Compare
… clamps HttpTarget acknowledges the source offset before the DLQ produce future settles, so foo's consumer offset cannot observe a failed produce. Check the dead topic high watermark instead. Co-authored-by: Cursor <cursoragent@cursor.com>
|
CI failure was a bad assertion in the new property test, not a passthrough bug.
Updated the test to assert the dead topic high watermark stays 0 when |
Problem
The dead letter producer's Kafka properties are not configurable.
KafkaClientFactory.createSenderOptions()andcreateProducer()set only the bootstrap/auth properties and the two serializers (src/main/java/kafka/KafkaClientFactory.java:76-88onmain), somax.request.sizeis stuck at the client default of 1,048,576.The consequence is that a record larger than 1 MiB cannot be dead-lettered at all. When the target fails and
DEAD_LETTER_TOPICis set,HttpTargetcallsproducer.produce(...), the send is rejected withRecordTooLargeException,Producer.produce's callback firesMonitor.produceError(error log +produce_errorcounter), and the future completes exceptionally — sodoOnSuccess/receiverOffset().acknowledge()never runs and the record sticks on the source topic instead of being parked for replay.This is not hypothetical: it is the blind spot behind goledge/kafka-message-reviver#538 sizing its dead-letter path for records up to 12 MiB. Every other ceiling on that path is settable; this one is not.
The consumer has the same shape of gap —
KAFKA_FETCH_MAX_BYTESandKAFKA_MAX_PARTITION_FETCH_BYTEShave dedicated parameters, but nothing else does.What changed
Two generic passthroughs, mirroring osskit/dafka-producer#38:
KAFKA_CONSUMER_PROPERTY_*KAFKA_CONSUMER_PROPERTY_MAX_PARTITION_FETCH_BYTES=5242880→max.partition.fetch.bytes=5242880KAFKA_PRODUCER_PROPERTY_*KAFKA_PRODUCER_PROPERTY_MAX_REQUEST_SIZE=5242880→max.request.size=5242880The name is stripped of its prefix, lowercased with
Locale.ROOT, and underscores become dots.Why two prefixes rather than one
dafka-producerhas a single Kafka client, so a singleKAFKA_PROPERTY_*prefix is unambiguous there.dafka-consumerhas two clients with disjoint property sets —max.request.sizeis meaningless to the consumer andmax.partition.fetch.bytesis meaningless to the producer. A single prefix applied to both would work but would make each client logThe configuration '...' was supplied but isn't a known configfor every property meant for the other one. Two prefixes keep it unambiguous and make the intent readable in a Helm values file.Precedence
Applied with
putIfAbsent, so a dedicated parameter always wins over the generic passthrough — the same outcome as #38'sfilterNot, and it also means the passthrough can never clobber the auth or serializer properties.Source of the variables
Read from
System.getenv()rather than fromDotenv, matching #38's use ofsys.env. The dedicated parameters keep going throughDotenv, so.envsupport for them is unchanged.Chart
extraEnvsupport is added in osskit/dafka-consumer-helm-chart#111, which also fixes a related rendering bug — see that PR.Verification
This PR is not verified, and cannot be until the image build is repaired. Being explicit about that rather than implying otherwise:
java -version→Unable to locate a Java Runtime), so the Java was not compiled locally.bazel build //src:image.taris broken onmain, independently of this change, which also meansyarn pretestand therefore the whole jest suite cannot run.WORKSPACE:56-60pins the archivedio_bazel_rules_dockerv0.25.0, whosecontainer_repositories()declareshttp_filetargets against a Google Cloud Storage bucket that no longer serves anonymous reads. Verified today:The
rules_docker-v0.25.0.tar.gzrelease asset itself still returns 200 — only the puller/loader binaries are gone, and they were only ever published to that bucket. This is the same breakage osskit/dafka-producer#40 is repairing there (rules_docker→rules_oci);dafka-producerneeded a base-image change too, but this repo already pullseclipse-temurin:18, which still resolves.The last green run here was
v13.3.1on 2026-02-08, so the bucket was withdrawn some time after that.The added spec
tests/specs/extraKafkaProperties.spec.tshas therefore never been executed. It isproduceToDeadLetterTopic.spec.tswithKAFKA_PRODUCER_PROPERTY_MAX_REQUEST_SIZE: '1024'added and a 4 KB payload: where that spec ends with the source offset committed at 1 after a successful dead-letter produce, this one asserts the offset is never committed, because the clampedmax.request.sizemakes the produce fail. If the passthrough did not reach the producer, the 4 KB record would dead-letter fine and the offset would be 1.The chart-side rendering is verified (
helm lint+helm template) in the chart PR.I have deliberately not taken on the
rules_docker→rules_ocimigration here — it is a separate concern from a config passthrough and belongs in its own PR, as it did fordafka-producer. Happy to open it if you'd like, but flagging rather than assuming.