-
Notifications
You must be signed in to change notification settings - Fork 925
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
Introduce ContextAwareRunnable|Callable|Function|Consume|BiConsumer|BiFunction #4890
Introduce ContextAwareRunnable|Callable|Function|Consume|BiConsumer|BiFunction #4890
Conversation
@@ -597,26 +597,18 @@ default ContextAwareBlockingTaskExecutor makeContextAware(BlockingTaskExecutor e | |||
* Returns a {@link Callable} that makes sure the current {@link RequestContext} is set and then invokes | |||
* the input {@code callable}. | |||
*/ | |||
default <T> Callable<T> makeContextAware(Callable<T> callable) { | |||
default <T> ContextAwareCallable<T> makeContextAware(Callable<T> callable) { |
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.
Changed the return type following the principle of "return the most specialized; accept the most generic".
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.
This seems like a breaking change even with API, not just ABI, something like Sorry was being silly - but is it confirmed to be ABI compatible?Callable aware = ctx.makeContextAware(notAware);
wouldn't compile anymore.
I guess callers would just need to stick with a type-cast until a major version bump could change the signature, or change the target milestone of the PR to v2.0.0
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 think you're right @anuraaga - this could break binary compatibility.
Let's change it back to play it safe?
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 yeah it seems safer to do that.
Just as an idea, static methods on RequestContext
would be an alternative to exposing new types
interface RequestContext {
static RequestContext from(Callable c)
static Callable unwrap(Callable c)
static RequestContext from(Runnable)
static Runnable unwrap(Runnable)
// etc
Naturally it seems like it could get unwieldy if adding even more methods, but if the expectation for that is low it could be viable, just an idea
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 sound idea to structure this. I think we might actually just wait until we can break the binary compatibility. Type-casting isn't too bad and is something I was going to do anyway as the place where I need context()
gives me only Runnable.
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.
It breaks binary compatibility. We had a similar discussion before. If a change works well with recompilation without modification of users' code, we allowed the change in minor upgrade.
ref: #4760
Simply recompiling your code should be enough in most cases because
BlockingTaskExecutor is a ScheduledExecutorService.
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.
Hmm - I have a server framework that uses Armeria that I haven't updated in a while as no new features added. It was nice that Armeria could still be updated in apps using it, and makeContextAware
is definitely used so will break. Didn't look at the link maybe it was already broken though 😅 Not a good thing to do in Java since usually you don't compile all your code.
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 can't say that we strictly follow semantic versioning. Agree on minimizing making breaking changes and maintaining API and ABI compatibility where possible.
That said, if we stick with semantic versioning, we'll have to keep putting things off and Armeria won't evolve easily until the next major version.
It is necessary making the current implicit versioning rule clearer and specify what can happen in a minor upgrade. For example, in the case of Spring Boot, when they release a new version, the previously deprecated functions in two minor versions ago are deleted.
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.
Strictly following semantic versioning will make us get to Armeria 9.0 fairly soon. 😄 We already introduced various ABI-breaking changes similar to this in 1.x unfortunately. Let's keep this PR as it is. Let us have some internal discussion on how we could handle this in our future releases.
fab26e4
to
7dd57a7
Compare
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 quick fix! 👍
core/src/main/java/com/linecorp/armeria/common/RequestContext.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/common/ContextAwareCallable.java
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/common/ContextAwareRunnable.java
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.
Left some super minor nits. Thanks @vkostyukov 🙇 👍 🚀
core/src/main/java/com/linecorp/armeria/common/DefaultContextAwareCallable.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/common/DefaultContextAwareCallable.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/common/DefaultContextAwareRunnable.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/common/RequestContext.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/common/RequestContext.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/common/RequestContext.java
Outdated
Show resolved
Hide resolved
7dd57a7
to
863c7a2
Compare
Still LGTM. |
* Returns a new {@link ContextAwareBiConsumer} that sets the specified {@link RequestContext} | ||
* before executing an underlying {@link BiConsumer}. | ||
*/ | ||
static <T, U> ContextAwareBiConsumer of(RequestContext context, BiConsumer<T, U> action) { |
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.
This adds two public APIs for doing the same thing I think
ContextAwareBiConsumer.of(ctx, action)
ctx.makeContextAware(action)
Probably it's better to avoid these factory methods since the context has them already
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 was mostly following the pattern that's already in place with things like ContextAwareExecutor.
Don't feel strongly about it either way but since we can't (yet) change the type returned from ctx.makeX
, maybe leaving another API (ContextAwareBiConsumer
) around isn't a bad idea to help users avoid type casting.
* this {@link ContextAwareBiConsumer}. | ||
*/ | ||
@Override | ||
RequestContext context(); |
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.
And another idea as another alternative to the static methods could be a common interface for context aware callbacks
interface ContextAwareCallback<T> {
RequestContext context();
T withoutContext();
}
class DefaultContextAwareBiConsumer<T, U> implements BiConsumer<T, U>, ContextAwareCallback<BiConsumer<T, U>> {
}
In the meantime if the caller needs to type cast, they would only have one type to worry about.
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'd actually imagine ContextHolder
would be a popular type-cast. At least, that's what I'm going to do internally.
863c7a2
to
827beeb
Compare
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.
Excellent work, @vkostyukov!
Motivation:
Users of Armeria APIs might need to be able to query the underlying
RequestContext
attached to a given "context-aware"Runnable
orCallable
. Let's name these anonymous classes and give then structure.Modifications:
ContextAwareRunnable
,ContextAwareCallable
DefaultContextAwareRunnable
,DefaultContextAwareCallable
Result:
ContextAwareRunnable
,ContextAwareCallable
and such #4878