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
Add ServiceOptions
and @ServiceOption
#5574
base: main
Are you sure you want to change the base?
Add ServiceOptions
and @ServiceOption
#5574
Conversation
I think we need to decide what settings the
|
Should we use the name |
A service can be wrapped with a decorator. If the decorator does not override public abstract class SimpleDecoratingHttpService ... {
@Override
public ServiceOptions options() {
return ((HttpService) unwrap()).options();
}
} |
It may be better. Let use |
core/src/main/java/com/linecorp/armeria/server/ServiceOptionsBuilder.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/ServiceOptions.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/ServiceOptions.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/ServiceOptions.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/ServiceConfigBuilder.java
Outdated
Show resolved
Hide resolved
I've renamed the class into |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #5574 +/- ##
============================================
+ Coverage 73.95% 74.11% +0.15%
- Complexity 20115 21328 +1213
============================================
Files 1730 1855 +125
Lines 74161 78816 +4655
Branches 9465 10069 +604
============================================
+ Hits 54847 58413 +3566
- Misses 14837 15691 +854
- Partials 4477 4712 +235 ☔ View full report in Codecov by Sentry. |
2cbba00
to
81e8d09
Compare
81e8d09
to
44f1946
Compare
There were some conflicts with my origin and upstream, so I'd reset the commits and did a force push 😓 |
core/src/main/java/com/linecorp/armeria/server/ServiceConfigBuilder.java
Outdated
Show resolved
Hide resolved
- requestTimeoutMillis - maxRequestLength - requestAutoAbortDelayMillis
9f73765
to
d65a265
Compare
private static final HttpServiceOptions WEB_SOCKET_DEFAULT_OPTIONS = HttpServiceOptions | ||
.builder() | ||
.requestTimeoutMillis(WebSocketUtil.DEFAULT_REQUEST_RESPONSE_TIMEOUT_MILLIS) | ||
.maxRequestLength(WebSocketUtil.DEFAULT_MAX_REQUEST_RESPONSE_LENGTH) | ||
.requestAutoAbortDelayMillis(WebSocketUtil.DEFAULT_REQUEST_AUTO_ABORT_DELAY_MILLIS) | ||
.build(); |
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.
Should we move this to WebSocketService
? I don't see we need to expose websocket()
here.
interface WebSocketService {
@Override
default HttpServiceOptions options() {
return DefaultWebSocketService.DEFAULT_OPTIONS;
}
}
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.
Shouldn't we override the options()
only in the DefaultWebSocketService
? Below test seems to allow DEFAULT_OPTIONS
for DefaultWebSocketService
only.
@Test
void shouldNotSetDefaultSettings() {
final ServiceConfig serviceConfig = server.server().serviceConfigs().get(0);
assertThat(serviceConfig.service().as(DelegatingWebSocketService.class)).isNotNull();
// The default settings for `WebSocketService` should be applied only to `DefaultWebSocketService`.
assertThat(serviceConfig.requestTimeoutMillis()).isEqualTo(Flags.defaultRequestTimeoutMillis());
}
core/src/main/java/com/linecorp/armeria/server/HttpServiceOptionsBuilder.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/HttpServiceOptionsBuilder.java
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/ServiceConfigBuilder.java
Outdated
Show resolved
Hide resolved
@@ -40,6 +40,7 @@ void webSocketServiceDefaultConfigValues() { | |||
assertThat(serviceConfig.requestAutoAbortDelayMillis()).isEqualTo( | |||
WebSocketUtil.DEFAULT_REQUEST_AUTO_ABORT_DELAY_MILLIS); | |||
|
|||
// TODO: Should we allow default HttpServiceOptions to override the default values from virtualHostTemplate |
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.
The priority of HttpServiceOptions
is between the values in ServiceBindingBuilder
and VirtualHostBuilder
.
The new priority of configurations will be: (Listed from high priority to low priority)
ServiceBindingBuilder
(highest)HttpServiceOptions
(if exists)VirtualHostBuilder
ServerBuilder
(lowest)
Based on the new priority, sb.requestAutoAbortDelayMillis(1000)
should not override HttpServiceOptions.requestAutoAbortDelayMillis()
if requestAutoAbortDelayMillis > -1
.
Should we test two scenarios?
- Make sure that
sb.requestAutoAbortDelayMillis(1000)
does NOT overrideserviceConfig.requestAutoAbortDelayMillis()
ofWebSocketService
- Make sure that
sb.route().requestAutoAbortDelayMillis(1000)
overridesWebSocketService.options().requestAutoAbortDelayMillis()
.
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've added above mentioned test scenarios in WebSocketServiceConfigTest#webSocketServiceOptionsPriority
.
- Move DEFAULT_OPTIONS of webSocket under DefaultWebSocketService - Add test to verify priority of the options
/** | ||
* Returns the {@link HttpServiceOptions} of this {@link HttpService}. | ||
*/ | ||
@Nullable |
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.
What are your thoughts on making this non-nullable like other methods?
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 make it as non-nullable as we can identify whether the user has set the value by checking whether the fields are set with values of -1 👍
core/src/main/java/com/linecorp/armeria/server/HttpServiceOptions.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/HttpServiceOptions.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/HttpServiceOptions.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/HttpServiceOptions.java
Outdated
Show resolved
Hide resolved
* Returns the server-side timeout of a request in milliseconds. | ||
*/ | ||
public HttpServiceOptionsBuilder requestTimeoutMillis(long requestTimeoutMillis) { | ||
this.requestTimeoutMillis = requestTimeoutMillis; |
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.
We need to check the value:
checkArgument(requestTimeoutMillis >= 0,
"requestTimeoutMillis: %s (expected: >= 0)", requestTimeoutMillis);
After that, we also need to modify these lines:
https://github.com/line/armeria/pull/5574/files#diff-2246967d4d345f650f2b3ec5d5032040fe494cc032094448c9c05c8557665449R188-R190
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.
Thank you for checking. I'll add validation logic and applied the changes to the specified code that you mentioned.
core/src/main/java/com/linecorp/armeria/server/ServiceConfigBuilder.java
Outdated
Show resolved
Hide resolved
import com.linecorp.armeria.server.HttpServiceOptions; | ||
|
||
/** | ||
* An annotation used to configure {@link HttpServiceOptions} of a {@link HttpService}. |
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.
nit:
* An annotation used to configure {@link HttpServiceOptions} of a {@link HttpService}. | |
* An annotation used to configure {@link HttpServiceOptions} of an {@link HttpService}. |
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've also changed a
to an
in the WrappingTransientHttpService
's doc.
* An annotation used to configure {@link HttpServiceOptions} of a {@link HttpService}. | ||
*/ | ||
@Retention(RetentionPolicy.RUNTIME) | ||
@Target({ ElementType.METHOD }) |
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.
What do you think of also adding ElementType.TYPE
?
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 support for ElementType.TYPE
🙇
@@ -397,4 +406,9 @@ public HttpResponse encode(ServiceRequestContext ctx, WebSocket out) { | |||
public WebSocketProtocolHandler protocolHandler() { | |||
return this; | |||
} | |||
|
|||
@Override | |||
public HttpServiceOptions options() { |
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.
We also need to add this to GraphqlWebSocketService
.
If a WebSocketService
fails to upgrade here:
armeria/core/src/main/java/com/linecorp/armeria/server/websocket/WebSocketService.java
Line 54 in 3963f2a
return upgradeResult.fallbackResponse(); |
we need to set the
HttpServiceOptions
from the fallbackService
.
@Nullable
HttpService fallbackService();
@Override
default HttpResponse serve(ServiceRequestContext ctx, HttpRequest req) throws Exception {
final WebSocketUpgradeResult upgradeResult = protocolHandler().upgrade(ctx, req);
if (!upgradeResult.isSuccess()) {
if (fallbackService() != null) {
ctx.setRequestTimeoutMillis(fallbackService().options().requestTimeoutMillis());
...
}
return upgradeResult.fallbackResponse();
}
final WebSocket in = protocolHandler().decode(ctx, req);
final WebSocket out = serve(ctx, in);
return protocolHandler().encode(ctx, out);
}
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.
What do you think of setting the HttpServiceOptions
in the DefaultWebSocketService#failOrFallback
method like below?
private HttpResponse failOrFallback(ServiceRequestContext ctx, HttpRequest req,
Supplier<HttpResponse> invalidResponse) throws Exception {
if (fallbackService != null) {
final HttpServiceOptions options = fallbackService.options();
if (options.requestTimeoutMillis() > 0) {
ctx.setRequestTimeoutMillis(options.requestTimeoutMillis());
}
...
return fallbackService.serve(ctx, req);
} else {
return invalidResponse.get();
}
}
The reason for above suggestion is because we can set HttpServiceOptions
while we are creating a fallback response. If we set HttpServiceOption
in WebSocketService
, handling fallback logic is separated into two parts
final WebSocketUpgradeResult upgradeResult = protocolHandler().upgrade(ctx, req);
: handles upgrade and create fallback response-
=> sets
if (fallbackService() != null) { ctx.setRequestTimeoutMillis(fallbackService().options().requestTimeoutMillis()); ... }
HttpServiceOptions
for the fallbackResponse
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.
What do you think of setting the HttpServiceOptions in the DefaultWebSocketService#failOrFallback method like below?
Oops, I missed it. Yeah we should set it in the location. 😉
Co-authored-by: minux <[email protected]>
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 we also need to update RouteDecoratingService
.
Motivation:
Allow users to set default options for a specific service
Modifications:
ServiceOptions
and@ServiceOption
annotation to allow users specify default optionsResult:
Users are able to set service specific options like below
or use annotation
ServiceOptions
toService
#5071. (If this resolves the issue.)