fix(connectors): preserve transformed payload schema across FFI#3669
Open
Standing-Man wants to merge 3 commits into
Open
fix(connectors): preserve transformed payload schema across FFI#3669Standing-Man wants to merge 3 commits into
Standing-Man wants to merge 3 commits into
Conversation
Sink transforms can change the Payload variant after the input stream has been decoded, but the runtime forwarded decoder.schema() to sink plugins. Plugins then reconstructed the transformed bytes using the stale input schema. Derive the schema from transformed payloads and use it for both FFI metadata containers. Reject mixed-schema messages within a batch and cover Raw-to-Text conversion at the FFI boundary. Signed-off-by: StandingMan <jmtangcs@gmail.com>
|
Thanks for the PR. It is labeled Slash commands (own line, regular comment) move it around the queue:
See CONTRIBUTING.md for details. |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #3669 +/- ##
=============================================
- Coverage 73.99% 51.60% -22.40%
Complexity 937 937
=============================================
Files 1301 1295 -6
Lines 147389 130496 -16893
Branches 122949 106357 -16592
=============================================
- Hits 109057 67339 -41718
- Misses 34861 60204 +25343
+ Partials 3471 2953 -518
🚀 New features to boost your workflow:
|
Contributor
Author
|
Hi @hubcio, could you please take a look when you have chance? Thanks. |
Contributor
|
@Standing-Man - Could you tell issue it is trying to solve and any related issue? |
Contributor
|
/author |
Contributor
Author
I’ve added more details to the PR description to better explain the problem this PR addresses. /request-review @ryerraguntla |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The runtime previously populated both
MessagesMetadata.schemaandRawMessages.schemafromdecoder.schema().decoder.schema()describes the input format configured for the Iggy stream. It remains unchanged for the lifetime of the consumer. However, format-conversion transforms can replace the decodedPayloadwith a differentvariant.
For example, consider a sink configured with a raw input stream and a transform that converts raw bytes to text:
Although the transform produced
Payload::Text, converting it back into bytes removed the Rust enum variant information. The only information available to the plugin for reconstructing the payload was the schema in the FFI metadata.Because the runtime still sent
Schema::Raw, the plugin reconstructed thetransformed bytes as
Payload::Raw. The transform appeared to succeed insidethe runtime, but its output type was lost when the message crossed the FFI
boundary.
The same problem is more serious for schema-sensitive conversions. For example:
Depending on the decoder and sink implementation, this could result in:
The transformed bytes were serialized correctly. The problem was that the runtime attached stale type information to those bytes.
Root cause
The runtime treated the configured input schema as if it were also the output
schema of the transform chain:
That assumption only holds for transforms that preserve the payload format. It is invalid for ProtoConvert, AvroConvert, FlatBufferConvert, and any other transform that changes the Payload variant. The runtime already had the correct type information in the transformed Payload, but it discarded that information when calling
Payload::try_into_vec().Rationale
The sink runtime decodes each Iggy message according to the schema configured
for the input stream and represents the decoded value as a
Payload. It thenapplies the configured transform chain before serializing the payload and
passing the batch to the sink plugin over FFI.
Format-conversion transforms can change the
Payloadvariant. For example, amessage decoded as
Payload::Rawcan becomePayload::Text, or a Protobufpayload can become JSON. Before this change, the runtime serialized the
transformed payload bytes but still attached
decoder.schema(), whichdescribes the input bytes before transformation.
The FFI boundary only carries serialized bytes and schema metadata. On the
plugin side,
SinkContainer::consumereconstructs eachPayloadby callingMessagesMetadata::schema.try_into_payload. A stale input schema thereforecaused the transformed bytes to be interpreted as the wrong payload type. A
Raw-to-Text transform could arrive as
Payload::Raw, while format-sensitiveconversions such as Protobuf-to-JSON could be rejected or decoded incorrectly.
What changed?
Payload::schema()now returns the schema represented by the current payloadvariant. The sink runtime reads that schema after all transforms have completed
and before the payload is converted back into bytes.
The transformed output schema is written to both existing FFI metadata
containers:
MessagesMetadata.schema, which the sink SDK uses to reconstruct payloads.RawMessages.schema, which keeps the serialized batch metadata consistent.A sink batch must have one output schema because the existing FFI batch format
stores schema once per batch. If a transformed message has a different schema
from the messages already accepted into the batch, the runtime logs the
mismatch, increments the connector error counter, and skips that message rather
than decoding it later with an incompatible schema.
If every message is filtered or rejected, the batch retains the original input
schema as a safe fallback.
This keeps the fix compatible with existing plugins. It does not change FFI
function signatures,
#[repr(C)]layouts, postcard payload structures, schemadiscriminants, or connector configuration.
A regression test exercises the complete runtime-to-plugin boundary with a
Raw-to-Text transform. The FFI callback deserializes both metadata structures
and verifies that they carry
Schema::Text, that the transformed bytes arepreserved, and that the batch reports one processed message.
Local Execution
passed
ran
AI Usage
unit tests, integration-style SDK tests, and representative plugin builds.