Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Allow empty payloads in Kafka, in order to support compaction tombstones #224

Merged
merged 5 commits into from
Aug 30, 2022

Conversation

mhelleborg
Copy link
Contributor

In order to support deletes for compacted topics, this PR allows empty / null payloads to be sent when using the Kafka extension. The previous requirement that the payload is present has been dropped, and tests added.

Ref Log compaction

…ombstones

Signed-off-by: Magne Helleborg <magne.helleborg@gmail.com>
@jskeet
Copy link
Contributor

jskeet commented Jul 26, 2022

I'll have a look at this when I get the chance, but I'm afraid it may be a while due to vacations. (I don't know anything about Kafka, which means it'll take me longer to try to work out whether I think it's a good idea or not...)

@jskeet jskeet self-assigned this Jul 26, 2022
@mhelleborg
Copy link
Contributor Author

Thanks Jon :)

The change should make it easy to use CloudEvents for projecting state using compacted topics, as a streaming KV-store.

The zero-length payloads are treated as tombstones, and lets Kafka clean up removed messages over time.

@jskeet
Copy link
Contributor

jskeet commented Aug 17, 2022

I still don't know why we prohibited empty messages in the first place. I'm going to ask at the meeting tomorrow. If other SDKs are fine with empty payloads, we should be too. If they're not, I want to find out why :)

@pierDipi
Copy link
Member

Commenting after the WG discussion.

I agree with this PR.

In general, Kafka records with a null value are valid records with both log compacted topics or with regular topics.

However, in the log compacted topics case, a record with a null value has a different semantic (tombstone), they signal to Kafka that it can remove all previous records with the same key but it retains and delivers to subscribers the tombstone record as long as it is consumed before the the topic-level configuration delete.retention.ms expires.

Since configuring a topic to be log compacted is an event producer's responsibility, the producer is specifically asking for that behavior so I don't see why it shouldn't be allowed to send a CloudEvent that is a tombstone given that:

  • the event itself is just a normal CloudEvent
  • the event producer is specifically asking the transport to have that side effect

@jskeet
Copy link
Contributor

jskeet commented Aug 18, 2022

Just to set expectations, I'm hoping to merge this PR next week - I'm on vacation tomorrow, and done with work for today.

Copy link
Contributor

@jskeet jskeet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved in general, with a few nits.

I'm going to create a PR for the Kafka binding spec at https://github.com/cloudevents/spec/blob/main/cloudevents/bindings/kafka-protocol-binding.md to mention that an empty payload can have a special meaning when using binary mode.

Source = new Uri("https://github.com/cloudevents/spec/pull/123"),
Id = "A234-1234-1234",
Time = new DateTimeOffset(2018, 4, 5, 17, 31, 0, TimeSpan.Zero),
DataContentType = contentType,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While not strictly invalid as far as I'm aware, is there any good reason to have a data content type when there isn't any data?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(It looks like you're using that to effectively check the result of decoding different empty bodies - I don't think that's really part of the Kafka code, so I think you can probably simplify this test. If you'd prefer to keep it, that's okay.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking it's a good idea to verify that the deserialization is well behaved across all the content types, even without a payload.

I can add the null content type as well, to be sure that it works correctly too.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But isn't that deserialization purely in the formatter, not in the Kafka code at all?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, it might be a case of over-testing. But I saw it as a better safe than sorry to cover it.

I can remove the content type checks if you wish?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't mind too much - it just seems unnecessary. I haven't looked at what the coverage is like at the moment.

test/CloudNative.CloudEvents.UnitTests/Kafka/KafkaTest.cs Outdated Show resolved Hide resolved
test/CloudNative.CloudEvents.UnitTests/Kafka/KafkaTest.cs Outdated Show resolved Hide resolved
Signed-off-by: Magne Helleborg <magne.helleborg@gmail.com>
Signed-off-by: Magne Helleborg <magne.helleborg@gmail.com>
Signed-off-by: Magne Helleborg <magne.helleborg@gmail.com>
Signed-off-by: Magne Helleborg <magne.helleborg@gmail.com>
@jskeet jskeet merged commit 81c82e0 into cloudevents:main Aug 30, 2022
jskeet added a commit to jskeet/sdk-csharp that referenced this pull request Sep 8, 2022
Changes since 2.3.1:

- Feature: Implement underscore prefixes for AMQP (see history) ([cloudevents#236](cloudevents#236)
- Feature: Allow empty payloads in Kafka ([cloudevents#224](cloudevents#224))
- Feature: Implement conversions to and from JObject/JsonElement in JsonEventFormatter ([cloudevents#234](cloudevents#234), part of [cloudevents#231](cloudevents#231))
- Bug fix: Observe JSON serializer options in JsonEventFormat ([cloudevents#226](cloudevents#226), fixes [cloudevents#225](cloudevents#225))
- Bug fix: Put AvroEventFormatter in the right namespace ([cloudevents#220](cloudevents#220), fixes [cloudevents#219](cloudevents#219))
- Bug fix: Use content headers when parsing HTTP requests/responses ([cloudevents#222](cloudevents#222), fixes [cloudevents#221](cloudevents#221))
- Bug fix: Perform release builds with ContinuousIntegrationBuild=true ([cloudevents#223](cloudevents#223), fixes [cloudevents#175](cloudevents#175))

Signed-off-by: Jon Skeet <jonskeet@google.com>
@jskeet jskeet mentioned this pull request Sep 8, 2022
jskeet added a commit to jskeet/sdk-csharp that referenced this pull request Sep 8, 2022
Changes since 2.3.1:

- Feature: Implement underscore prefixes for AMQP (see history) ([cloudevents#236](cloudevents#236)
- Feature: Allow empty payloads in Kafka ([cloudevents#224](cloudevents#224))
- Feature: Implement conversions to and from JObject/JsonElement in JsonEventFormatter ([cloudevents#234](cloudevents#234), part of [cloudevents#231](cloudevents#231))
- Bug fix: Observe JSON serializer options in JsonEventFormat ([cloudevents#226](cloudevents#226), fixes [cloudevents#225](cloudevents#225))
- Bug fix: Put AvroEventFormatter in the right namespace ([cloudevents#220](cloudevents#220), fixes [cloudevents#219](cloudevents#219))
- Bug fix: Use content headers when parsing HTTP requests/responses ([cloudevents#222](cloudevents#222), fixes [cloudevents#221](cloudevents#221))
- Bug fix: Perform release builds with ContinuousIntegrationBuild=true ([cloudevents#223](cloudevents#223), fixes [cloudevents#175](cloudevents#175))

Signed-off-by: Jon Skeet <jonskeet@google.com>
jskeet added a commit to jskeet/sdk-csharp that referenced this pull request Sep 8, 2022
Changes since 2.3.1:

- Feature: Implement underscore prefixes for AMQP (see history) ([cloudevents#236](cloudevents#236)
- Feature: Allow empty payloads in Kafka ([cloudevents#224](cloudevents#224))
- Feature: Implement conversions to and from JObject/JsonElement in JsonEventFormatter ([cloudevents#234](cloudevents#234), part of [cloudevents#231](cloudevents#231))
- Bug fix: Observe JSON serializer options in JsonEventFormat ([cloudevents#226](cloudevents#226), fixes [cloudevents#225](cloudevents#225))
- Bug fix: Put AvroEventFormatter in the right namespace ([cloudevents#220](cloudevents#220), fixes [cloudevents#219](cloudevents#219))
- Bug fix: Use content headers when parsing HTTP requests/responses ([cloudevents#222](cloudevents#222), fixes [cloudevents#221](cloudevents#221))
- Bug fix: Perform release builds with ContinuousIntegrationBuild=true ([cloudevents#223](cloudevents#223), fixes [cloudevents#175](cloudevents#175))

Signed-off-by: Jon Skeet <jonskeet@google.com>
jskeet added a commit to jskeet/sdk-csharp that referenced this pull request Sep 8, 2022
Changes since 2.3.1:

- Feature: Implement underscore prefixes for AMQP (see history) ([cloudevents#236](cloudevents#236))
- Feature: Allow empty payloads in Kafka ([cloudevents#224](cloudevents#224))
- Feature: Implement conversions to and from JObject/JsonElement in JsonEventFormatter ([cloudevents#234](cloudevents#234), part of [cloudevents#231](cloudevents#231))
- Bug fix: Observe JSON serializer options in JsonEventFormat ([cloudevents#226](cloudevents#226), fixes [cloudevents#225](cloudevents#225))
- Bug fix: Put AvroEventFormatter in the right namespace ([cloudevents#220](cloudevents#220), fixes [cloudevents#219](cloudevents#219))
- Bug fix: Use content headers when parsing HTTP requests/responses ([cloudevents#222](cloudevents#222), fixes [cloudevents#221](cloudevents#221))
- Bug fix: Perform release builds with ContinuousIntegrationBuild=true ([cloudevents#223](cloudevents#223), fixes [cloudevents#175](cloudevents#175))

Signed-off-by: Jon Skeet <jonskeet@google.com>
jskeet added a commit that referenced this pull request Sep 8, 2022
Changes since 2.3.1:

- Feature: Implement underscore prefixes for AMQP (see history) ([#236](#236))
- Feature: Allow empty payloads in Kafka ([#224](#224))
- Feature: Implement conversions to and from JObject/JsonElement in JsonEventFormatter ([#234](#234), part of [#231](#231))
- Bug fix: Observe JSON serializer options in JsonEventFormat ([#226](#226), fixes [#225](#225))
- Bug fix: Put AvroEventFormatter in the right namespace ([#220](#220), fixes [#219](#219))
- Bug fix: Use content headers when parsing HTTP requests/responses ([#222](#222), fixes [#221](#221))
- Bug fix: Perform release builds with ContinuousIntegrationBuild=true ([#223](#223), fixes [#175](#175))

Signed-off-by: Jon Skeet <jonskeet@google.com>
ericdotnet added a commit to ericdotnet/CSharp-sdk-dev that referenced this pull request May 13, 2024
Changes since 2.3.1:

- Feature: Implement underscore prefixes for AMQP (see history) ([#236](cloudevents/sdk-csharp#236))
- Feature: Allow empty payloads in Kafka ([#224](cloudevents/sdk-csharp#224))
- Feature: Implement conversions to and from JObject/JsonElement in JsonEventFormatter ([#234](cloudevents/sdk-csharp#234), part of [#231](cloudevents/sdk-csharp#231))
- Bug fix: Observe JSON serializer options in JsonEventFormat ([#226](cloudevents/sdk-csharp#226), fixes [#225](cloudevents/sdk-csharp#225))
- Bug fix: Put AvroEventFormatter in the right namespace ([#220](cloudevents/sdk-csharp#220), fixes [#219](cloudevents/sdk-csharp#219))
- Bug fix: Use content headers when parsing HTTP requests/responses ([#222](cloudevents/sdk-csharp#222), fixes [#221](cloudevents/sdk-csharp#221))
- Bug fix: Perform release builds with ContinuousIntegrationBuild=true ([#223](cloudevents/sdk-csharp#223), fixes [#175](cloudevents/sdk-csharp#175))

Signed-off-by: Jon Skeet <jonskeet@google.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants