-
Notifications
You must be signed in to change notification settings - Fork 41.1k
Add auto-configuration for Kafka Retry Topics #29812
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
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR. I've made some suggestions for your consideration.
...utoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java
Outdated
Show resolved
Hide resolved
.../src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationUtils.java
Outdated
Show resolved
Hide resolved
...igure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfiguration.java
Outdated
Show resolved
Hide resolved
...utoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add the new properties to the A.8. Integration Properties section of the documentation
That part of the doc is auto-generated by source code. So, whatever you have added to KafkaProperties
is going to be reflected over there as well.
...igure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfiguration.java
Outdated
Show resolved
Hide resolved
.../src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationUtils.java
Outdated
Show resolved
Hide resolved
...igure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfiguration.java
Outdated
Show resolved
Hide resolved
e2885fd
to
f80469d
Compare
Thank you very much for the reviews. I've made the changes as suggested. I removed the BackOff inner class since it'd have the same problem of creating a group with a dash in the name. Also, most of the BackOff creation logic and JavaDocs are from the Spring Retry project, not sure if we should add proper credit there somehow. Let me know if there are any other suggestions or anything else to change. Thanks. |
...igure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfiguration.java
Outdated
Show resolved
Hide resolved
Improve retry topic tests Add default values to Retry Topic Properties
.maxDelay(retryTopic.getMaxDelayMillis()).multiplier(retryTopic.getMultiplier()) | ||
.random(retryTopic.isRandomBackOff()).build(); | ||
Assert.isInstanceOf(SleepingBackOffPolicy.class, policy, | ||
() -> "BackOffPolicy must be an instance of SleepingBackOffPolicy. Provided: " + policy); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it is OK to say this: the maximum what end-user can provide are exactly those props you use for BackOffPolicyBuilder
.
So, we might need to ensure that only SleepingBackOffPolicy
is created. Perhaps just ignore some props which are not sufficient...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for looking into this @artembilan. Currently, the BackOffPolicyBuilder
only returns instances of SleepingBackOffPolicy
, but I didn't want to add this constraint to the builder's method signature.
So this assertion here is just for the case that, if we in the future update the Builder
to for example return a NoBackOffPolicy
if delay is set to 0
, we don't get a class cast exception, but get this error instead.
But I agree that this is not a really useful message to the user. Maybe we should just blindly cast? Not sure what a useful message for the users should be in this case, since it'd not really be their fault.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we don't support a delay == 0
, then it has to be rejected as a configuration properties validation, before calling this builder.
What I mean, if we don't support anything else in the builder, then we need to ensure the props provided for it are in the valid range.
The message you say now is fully misleading: end-user does not create instances of this, so the message (if any), must really point what is wrong with end-user config.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, currently if the provided delay < 1 it is set to 1 in the FixedBackOffPolicy
, and most or all other BackOffPolicy
implementations follow that pattern. In RetryTopic
's annotation processing and builder I chose to mimic Spring Retry
behavior as much as possible, since we relied on the same @BackOff
annotation.
I've been meaning to ask if maybe we should change this in Spring Retry
to return the NoBackOffPolicy
instead if delay=0
is provided, but didn't want to mix things up. Also, that seems like a breaking change, so it should be a good fit only for SR
2.0.
Maybe it'd be worth it to validate user input here to make sure the inputs are > or >= 0. Although it might be confusing having different behaviors for auto configuration and the @RetryableTopic
annotation and builder.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, why then does RetryTopicConfigurationBuilder
support only a SleepingBackOffPolicy
?
Why it cannot be that super BackOffPolicy
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's because the way we generate the delay values is we inject a Sleeper
implementation in the BackOffPolicy
that calls backOff
and stores the values, so we need that any custom policy the user provides respect the SleepingBackOffPolicy
contract.
The builder offers a noBackOff()
method if that's what the user desires, and if that's the case we don't need the Sleeper
to fetch the values.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see there public RetryTopicConfigurationBuilder noBackoff() {
, so perhaps with some props config we can fall back to this instead of customBackoff()
then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean, if users set delay=0
we could set noBackOff()
for them there? That's an interesting thought. My concern would be having different behaviors in auto configuration and annotation processing - would that be confusing for users? I guess since these are kind of corner cases, maybe we can depart from that and also add properties validation.
WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that would be reasonable.
Thanks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I’ll add that then. Thanks a lot for your input!
.suffixTopicsWithIndexValues().doNotAutoCreateRetryTopics().create(kafkaOperations); | ||
} | ||
|
||
private SleepingBackOffPolicy<?> getBackOffPolicy(Topic retryTopic) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
static
/** | ||
* In the exponential case (multiplier() > 0) set this to true to have the | ||
* backoff delays randomized, so that the maximum delay is multiplier times | ||
* the previous delay and the distribution is uniform between the two values. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A description for these configuration properties must be as short as possible: https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#appendix.configuration-metadata.format.property
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. This description was extracted from the @BackOff
annotation, I'll try to come up with something more succinct. Thanks.
.maxDelay(retryTopic.getMaxDelayMillis()).multiplier(retryTopic.getMultiplier()) | ||
.random(retryTopic.isRandomBackOff()).build(); | ||
Assert.isInstanceOf(SleepingBackOffPolicy.class, policy, | ||
() -> "BackOffPolicy must be an instance of SleepingBackOffPolicy. Provided: " + policy); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, why then does RetryTopicConfigurationBuilder
support only a SleepingBackOffPolicy
?
Why it cannot be that super BackOffPolicy
?
4d97b6b
to
b698f85
Compare
Implemented @artembilan's suggestions. I looked into using Please let me know if there's a better way or anything else to change. Thanks |
Add properties validation Add noBackOffPolicy for zero delay Improve javadocs
5e45bea
to
708be91
Compare
I've cleaned up the validation logic and added tests for that. Please let me know if there's anything else. Thanks! |
@@ -1447,6 +1454,23 @@ public void setRandomBackOff(Boolean randomBackOff) { | |||
this.randomBackOff = randomBackOff; | |||
} | |||
|
|||
private Topic validate() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I won't mind, but I don't know Spring Boot development process in details, so I'll defer a decision for a proper validation and its place to respective Spring Boot team members.
Thanks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, thanks. Just for reference, it seems we already have some validation in this buildProperties
method of the KafkaProperties
class, so I thought it seemed ok there. Of course, I'm ok with validating any other way or place.
Lines 1216 to 1218 in c58e24a
public Map<String, Object> buildProperties() { | |
validate(); | |
Properties properties = new Properties(); |
Thanks for looking into this.
FYI, this unrelated test failed in the PR build: Found test failures in 1 test task:
[00:00:08](https://ci.spring.io/builds/185388#L62321ef2:5476)
[00:00:08](https://ci.spring.io/builds/185388#L62321ef2:5477)
:spring-boot-project:spring-boot-devtools:test
[00:00:08](https://ci.spring.io/builds/185388#L62321ef2:5478)
org.springframework.boot.devtools.tunnel.server.HttpTunnelServerTests > disconnectTimeout()` I'll force-push a no-ops commit to trigger the PR build again. Thanks. |
Add validation for randomBackOff with policy not exponential Add test case
d29ff6a
to
73439a5
Compare
@garyrussell, if and when possible, I'd like your input on the chosen
The other defaults are the same as for the rest of the feature, Thanks. |
Hi @snicoll and @wilkinsona, looks like from the Spring Kafka team's perspective there are no further concerns. Is there anything you'd like to be changed implementation-wise? We can revise any part of this based on user feedback for 2.7. Thanks |
Thanks for the follow-up and for working with the team. Time is running out with RC1 happening tomorrow. I will do my best to review it before that happens if possible. |
Sure, no worries. I should be available if there's anything to be changed prior to the release. Thanks. |
@tomazfernandes thank you for making your first contribution to Spring Boot. If you're interested, I've polished your contribution in b3e3581, mostly about using primitive types if possible. I also decided to remove the validation business as we don't really do such a thing in configuration properties usually. We'd rather let the underlying component we configure throw an exception if necessary. |
Thanks a lot @snicoll for finding the time to look into this in such short notice! The retryable topics feature has been gaining a lot of traction with the community and with auto configuration I'm sure more users will be able to benefit from it and in a simpler way. I had missed that if users had more than one I wonder if it would make sense to add a Or maybe that's expected behavior - if users choose to define multiple What do you think? Thanks again! |
That's not what |
I see, makes sense. I've learned a lot about autoconfiguration and what it is and isn't supposed to do in this issue, so thanks a lot everyone involved. Thanks again @snicoll for looking into this in time for the |
Closes #28450
This PR adds basic auto-configuration capabilities for Spring Kafka's non-blocking delayed retries feature (https://docs.spring.io/spring-kafka/reference/html/#retry-topic).
I chose not to add exception type classification to it just now as was previously suggested by @garyrussell so I can get feedback on the basic solution first. I can add exception type classification in a separate PR if and when this one is approved.
I wasn't sure whether to add an entry to the Messaging section of the documentation, since it seems to cover more basic use cases. I can do so if that's the case.
Seems like we should add the new properties to the A.8. Integration Properties section of the documentation, but I couldn't really find it in the source code. I can add it if you point me to it.
Please feel free to request any changes you see fit, or to make a polish commit on top of it.
As always, If @garyrussell and @artembilan can take a look into this it'd be great.
Thanks