[
https://issues.apache.org/jira/browse/NIFI-16350?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18132563#comment-18132563
]
Ankur Kotwal. commented on NIFI-16350:
--------------------------------------
I would like to work on this. Before opening a PR, I want to agree on the
intended RECORD-strategy behavior, since it is a user-visible change.
Current state: Kafka3ConsumerService (and RecordIterable) replace a null value
with new byte[0] before building the ByteRecord, so downstream code cannot tell
a tombstone from a non-null empty value. FlowFileStreamKafkaMessageConverter
infers a tombstone from value.length == 0, and
AbstractRecordStreamKafkaMessageConverter passes the empty value to the Record
Reader, which fails for readers that need a header (Protobuf with
ConfluentEncodedSchemaReferenceReader, Avro with a schema-registry encoded
header).
Proposal:
1. Carry the distinction explicitly: add a boolean "tombstone" to ByteRecord
(null value -> tombstone=true, value stays byte[0] so existing callers keep
working), set it in Kafka3ConsumerService and RecordIterable.
2. FLOW_FILE strategy: set kafka.tombstone=true only when the record is a real
tombstone, not for a non-null empty value.
3. RECORD strategy (and the "Parse Records" verification step): do not hand
tombstones to the Record Reader. Options:
a) route each tombstone to the success relationship as a separate empty
FlowFile with kafka.tombstone=true (consistent with FLOW_FILE), or
b) for the USE_WRAPPER output strategy, emit a wrapper record whose value is
null; for USE_VALUE, use (a).
4. Verification: count tombstones separately and report them instead of failing
"Parse Records".
My preference is (a) for USE_VALUE and (b) for USE_WRAPPER, since PublishKafka
already treats a null wrapper value as a tombstone, so a ConsumeKafka ->
PublishKafka round trip would preserve tombstones.
Does this direction work for the maintainers? I'm happy to adjust before I
start on the PR.
> ConsumeKafka RECORD strategy and verification treat Kafka tombstones as parse
> failures
> --------------------------------------------------------------------------------------
>
> Key: NIFI-16350
> URL: https://issues.apache.org/jira/browse/NIFI-16350
> Project: Apache NiFi
> Issue Type: Bug
> Reporter: Wojciech Trefon
> Priority: Major
>
> h2. Summary
> A Kafka tombstone is a record with a non-null key and a null value. When
> ConsumeKafka uses the RECORD processing strategy, tombstones are passed to
> the configured Record Reader as zero-length content.
> With StandardProtobufReader and ConfluentEncodedSchemaReferenceReader, this
> causes tombstones to be treated as malformed Protobuf records. The same
> record also causes ConsumeKafka verification to fail in the Parse Records
> step.
> h2. Steps to reproduce
> # Publish a Kafka record with a non-null key and a null value.
> # Configure ConsumeKafka with Processing Strategy set to RECORD.
> # Configure StandardProtobufReader with ConfluentEncodedSchemaReferenceReader.
> # Stop ConsumeKafka and run Verify.
> # Observe that the Parse Records verification step fails on the tombstone.
> # Start ConsumeKafka normally.
> # Observe that the tombstone is routed as a parse failure while the consumer
> offset advances.
> h2. Actual behavior
> Verify reports an error similar to:
> {code}
> Parse Records
> Failed to parse Record number 9:
> org.apache.nifi.schema.access.SchemaNotFoundException: Failed to read header
> in first 5 bytes from stream
> {code}
> During normal RECORD processing, the zero-length value reaches
> StandardProtobufReader and is routed to the parse failure relationship. If
> that relationship is auto-terminated, the tombstone is silently discarded
> while consumption continues and the offset advances.
> This differs from FLOW_FILE processing, where a tombstone can be represented
> by an empty FlowFile with the kafka.tombstone attribute set to true and
> routed through success.
> h2. Expected behavior
> A valid Kafka tombstone should not be classified as a malformed Protobuf
> record solely because it has no schema header. Verification and normal
> processing should handle the same tombstone consistently and preserve the
> distinction between a null Kafka value and a non-null empty value.
> h2. Code observation
> Kafka3ConsumerService converts a null ConsumerRecord value to a zero-length
> byte array before RECORD processing. At that point, downstream record parsing
> cannot distinguish a tombstone from a non-null empty value.
> h2. Related issues
> * [NIFI-12371|https://issues.apache.org/jira/browse/NIFI-12371] added
> tombstone support for non-record Kafka processors and noted that record-based
> processors might require separate handling.
> * [NIFI-14122|https://issues.apache.org/jira/browse/NIFI-14122] and
> [NIFI-14123|https://issues.apache.org/jira/browse/NIFI-14123] restored
> tombstone support in Kafka publish paths.
> * [NIFI-14247|https://issues.apache.org/jira/browse/NIFI-14247] covers
> ConsumeKafka tombstones in FLOW_FILE processing.
> The related issues do not cover ConsumeKafka RECORD processing or the Verify
> Parse Records step.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)