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

GH-3067: Draft of mapping multiple headers with same key #3101

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

poznachowski
Copy link

Draft of mapping iterable headers

Copy link
Member

@artembilan artembilan left a comment

Choose a reason for hiding this comment

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

I'm OK with the solution.
Please, consider to run gradlew check locally, so you will see Checkstyle violations.
Thanks

Copy link
Member

@artembilan artembilan left a comment

Choose a reason for hiding this comment

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

Please, also add your name to the @author list of the affected classes.
The whats-new.adoc deserves a new entry for this new feature.
And headers.adoc must be improved about this new behavior.

I also see that you did nothing for the DefaultKafkaHeaderMapper.
Probably the logic you have introduced can go into the AbstractKafkaHeaderMapper ?

@poznachowski
Copy link
Author

Yes of course. This was just a starter to make sure I'm on the right track.

@sobychacko
Copy link
Contributor

@poznachowski, Any updates on this? We have a release coming up next week. If you want this to be part of that release, we need to start further review on this PR sooner.

@poznachowski
Copy link
Author

I should have something ready tomorrow.

@poznachowski
Copy link
Author

I updated my MR with initial version (not polished) of DefaultHeaderKafkaMapper. It's more complicated than I thought.
The need of handling spring_json_header_types header makes it harder to extract common logic to the AbstractKafkaHeaderMapper.
I'm not really sure if my solution will hold. I see that RecordHeaders uses List internally, but is it enough to guarantee that Kafka ensures headers order?
Additionally, the change makes DeliveryHeaderTests fail. retry_topic-attempts header becomes now a list with 2 entries and getNonBlockingRetryDeliveryAttempt method fails. Haven't investigated it yet.

@sobychacko
Copy link
Contributor

sobychacko commented Mar 14, 2024

@poznachowski We moved the milestone to 3.2.0-RC1, which is the April release, so you have some time to polish things. Please let us know when it is ready for the actual review. The approach that you take in the PR is in the right direction (generally speaking). Could you polish and make sure that there are no checkstyle issues, etc.? Then we will do more formal reviews.

@poznachowski
Copy link
Author

@sobychacko sure, should have it ready somewhere beginning next week.

@sobychacko
Copy link
Contributor

@poznachowski Any updates on this PR?

@poznachowski poznachowski force-pushed the GH-3067 branch 7 times, most recently from bc7933b to ac22919 Compare March 29, 2024 10:23
@poznachowski
Copy link
Author

I'd like to say that I have all ready, but I found some Spring specific header inconsistencies and struggling with picking the right approach.

retainAllRetryHeaderValues flag in DeadLetterPublishingRecovererFactory allows to have multiple headers on Kafka-side for given header types (especially RetryTopicHeaders.DEFAULT_HEADER_ATTEMPTS). When these were mapped onto Spring Message only the last one was always retained allowing to simply use @Header(name = RetryTopicHeaders.DEFAULT_HEADER_ATTEMPTS, required = false) Integer nonBlockingAttempts (as in DeliveryHeaderTests). As I was unware of usage of such headers, the current state of my MR allows to map these to a potential List on Spring side.
This has developed into another problem. Spring was still able to map List of values onto a single element with usage of CollectionToObjectConverter. The converter is taking first element thought. To overcome this and allow potential backwards compatibility I decided to reverse the list order while mapping.
Current solution is also inconsistent as I decided to keep only last values for headers such as: KafkaHeaders.DELIVERY_ATTEMPT, KafkaHeaders.LISTENER_INFO, KafkaUtils.KEY_DESERIALIZER_EXCEPTION_HEADER and KafkaUtils.VALUE_DESERIALIZER_EXCEPTION_HEADER as they where already specified in the DefaultKafkaHeaderMapper mapper. When I tried to allow multiple values for KafkaHeader.DELIVERY_ATTEMPT multiple test issues arose.

Having said that I'd suggest to keep a list of Spring 'technical' Kafka headers that should never be mapped into a collection on the Spring side (only last values should be kept). This would avoid unnecessary changes in the code (especially in the retrytopic package). If this plus reversing list order (so CollectionToObjectConverter can pick up the last value for backwards compatibility) sounds fine to you I can proceed with polishing and providing appropriate documentation.

@sobychacko
Copy link
Contributor

@poznachowski Sorry for the delay in responding to you. The approach you mentioned for keeping the internal metadata type headers as only single-value item makes sense. As long as it doesn't bring any backward compatibility issues, it's ok to reverse the order. Please re-work the PR and when ready, remove the draft status, so that we can start a formal PR review. Thanks!

@@ -97,6 +102,7 @@ public class DefaultKafkaHeaderMapper extends AbstractKafkaHeaderMapper {
* {@code "!id", "!timestamp" and "*"}. In addition, most of the headers in
* {@link KafkaHeaders} are never mapped as headers since they represent data in
* consumer/producer records.
*
Copy link
Member

Choose a reason for hiding this comment

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

Please, consider to not reformat Javadocs: no empty lines for methods.

}
jsonHeaders.put(headerIndex == null ?
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure what you are doing here, but I think all the framework headers must be as a single value Kafka headers anyway. There are a lot of logic in the framework which relies on them.
We just must agree that we have to make a fix only for end-user headers which can be iterable.
Even if that JSON headers looks like a collection, it is really something what the framework rely on as as single header.
So, I don't expect too drastic changes in this area.
Thanks.

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