diff --git a/framework-docs/src/docs/asciidoc/integration/rest-clients.adoc b/framework-docs/src/docs/asciidoc/integration/rest-clients.adoc index 8a47198d4b10..2ee33cc1d6ac 100644 --- a/framework-docs/src/docs/asciidoc/integration/rest-clients.adoc +++ b/framework-docs/src/docs/asciidoc/integration/rest-clients.adoc @@ -497,6 +497,11 @@ Annotated, HTTP exchange methods support the following return values: TIP: You can also use any other async or reactive types registered in the `ReactiveAdapterRegistry`. +TIP: For non-reactive types, blocking from a reactive publisher is performed +under the hood by the framework. By default, it is done without a timeout. +You can set a timeout for blocking by calling `blockTimeout(Duration blockTimeout)` +on `HttpServiceProxyFactory.Builder`. + [[rest-http-interface-exceptions]] === Exception Handling diff --git a/framework-docs/src/docs/asciidoc/rsocket.adoc b/framework-docs/src/docs/asciidoc/rsocket.adoc index 4da739d73c71..3805a2be238d 100644 --- a/framework-docs/src/docs/asciidoc/rsocket.adoc +++ b/framework-docs/src/docs/asciidoc/rsocket.adoc @@ -979,3 +979,8 @@ method parameters: Annotated, RSocket exchange methods support return values that are concrete value(s), or any producer of value(s) that can be adapted to a Reactive Streams `Publisher` via `ReactiveAdapterRegistry`. + +TIP: For non-reactive types, blocking from a reactive publisher is performed +under the hood by the framework. By default, it is done without a timeout. +You can set a timeout for blocking by calling `blockTimeout(Duration blockTimeout)` +on `RSocketServiceProxyFactory.Builder`. \ No newline at end of file diff --git a/spring-messaging/src/main/java/org/springframework/messaging/rsocket/service/RSocketServiceMethod.java b/spring-messaging/src/main/java/org/springframework/messaging/rsocket/service/RSocketServiceMethod.java index 29b0c796e95b..db26f744f8a5 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/rsocket/service/RSocketServiceMethod.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/rsocket/service/RSocketServiceMethod.java @@ -67,7 +67,7 @@ final class RSocketServiceMethod { RSocketServiceMethod( Method method, Class containingClass, List argumentResolvers, RSocketRequester rsocketRequester, @Nullable StringValueResolver embeddedValueResolver, - ReactiveAdapterRegistry reactiveRegistry, Duration blockTimeout) { + ReactiveAdapterRegistry reactiveRegistry, @Nullable Duration blockTimeout) { this.method = method; this.parameters = initMethodParameters(method); @@ -125,7 +125,7 @@ private static String initRoute( private static Function initResponseFunction( RSocketRequester requester, Method method, - ReactiveAdapterRegistry reactiveRegistry, Duration blockTimeout) { + ReactiveAdapterRegistry reactiveRegistry, @Nullable Duration blockTimeout) { MethodParameter returnParam = new MethodParameter(method, -1); Class returnType = returnParam.getParameterType(); @@ -164,8 +164,10 @@ else if (reactiveAdapter == null) { return reactiveAdapter.fromPublisher(responsePublisher); } return (blockForOptional ? - ((Mono) responsePublisher).blockOptional(blockTimeout) : - ((Mono) responsePublisher).block(blockTimeout)); + (blockTimeout != null ? ((Mono) responsePublisher).blockOptional(blockTimeout) : + ((Mono) responsePublisher).blockOptional()) : + (blockTimeout != null ? ((Mono) responsePublisher).block(blockTimeout) : + ((Mono) responsePublisher).block())); }); } diff --git a/spring-messaging/src/main/java/org/springframework/messaging/rsocket/service/RSocketServiceProxyFactory.java b/spring-messaging/src/main/java/org/springframework/messaging/rsocket/service/RSocketServiceProxyFactory.java index f4480923f5b6..076cb862b2aa 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/rsocket/service/RSocketServiceProxyFactory.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/rsocket/service/RSocketServiceProxyFactory.java @@ -59,13 +59,14 @@ public final class RSocketServiceProxyFactory { private final ReactiveAdapterRegistry reactiveAdapterRegistry; + @Nullable private final Duration blockTimeout; private RSocketServiceProxyFactory( RSocketRequester rsocketRequester, List argumentResolvers, @Nullable StringValueResolver embeddedValueResolver, - ReactiveAdapterRegistry reactiveAdapterRegistry, Duration blockTimeout) { + ReactiveAdapterRegistry reactiveAdapterRegistry, @Nullable Duration blockTimeout) { this.rsocketRequester = rsocketRequester; this.argumentResolvers = argumentResolvers; @@ -139,7 +140,7 @@ public static final class Builder { private ReactiveAdapterRegistry reactiveAdapterRegistry = ReactiveAdapterRegistry.getSharedInstance(); @Nullable - private Duration blockTimeout = Duration.ofSeconds(5); + private Duration blockTimeout; private Builder() { } @@ -189,7 +190,8 @@ public Builder reactiveAdapterRegistry(ReactiveAdapterRegistry registry) { /** * Configure how long to wait for a response for an HTTP service method * with a synchronous (blocking) method signature. - *

By default this is 5 seconds. + *

By default this is {@code null}, + * in which case means blocking on publishers is done without a timeout. * @param blockTimeout the timeout value * @return this same builder instance */ @@ -207,7 +209,7 @@ public RSocketServiceProxyFactory build() { return new RSocketServiceProxyFactory( this.rsocketRequester, initArgumentResolvers(), this.embeddedValueResolver, this.reactiveAdapterRegistry, - (this.blockTimeout != null ? this.blockTimeout : Duration.ofSeconds(5))); + this.blockTimeout); } private List initArgumentResolvers() { diff --git a/spring-web/src/main/java/org/springframework/web/service/invoker/HttpServiceMethod.java b/spring-web/src/main/java/org/springframework/web/service/invoker/HttpServiceMethod.java index 701d640d8979..2a01b0baeee5 100644 --- a/spring-web/src/main/java/org/springframework/web/service/invoker/HttpServiceMethod.java +++ b/spring-web/src/main/java/org/springframework/web/service/invoker/HttpServiceMethod.java @@ -71,7 +71,7 @@ final class HttpServiceMethod { HttpServiceMethod( Method method, Class containingClass, List argumentResolvers, HttpClientAdapter client, @Nullable StringValueResolver embeddedValueResolver, - ReactiveAdapterRegistry reactiveRegistry, Duration blockTimeout) { + ReactiveAdapterRegistry reactiveRegistry, @Nullable Duration blockTimeout) { this.method = method; this.parameters = initMethodParameters(method); @@ -275,7 +275,7 @@ private static List initAccept(@Nullable HttpExchange typeAnnot, Http private record ResponseFunction( Function> responseFunction, @Nullable ReactiveAdapter returnTypeAdapter, - boolean blockForOptional, Duration blockTimeout) { + boolean blockForOptional, @Nullable Duration blockTimeout) { private ResponseFunction( Function> responseFunction, @@ -298,8 +298,10 @@ public Object execute(HttpRequestValues requestValues) { } return (this.blockForOptional ? - ((Mono) responsePublisher).blockOptional(this.blockTimeout) : - ((Mono) responsePublisher).block(this.blockTimeout)); + (this.blockTimeout != null ? ((Mono) responsePublisher).blockOptional(this.blockTimeout) : + ((Mono) responsePublisher).blockOptional()) : + (this.blockTimeout != null ? ((Mono) responsePublisher).block(this.blockTimeout) : + ((Mono) responsePublisher).block())); } diff --git a/spring-web/src/main/java/org/springframework/web/service/invoker/HttpServiceProxyFactory.java b/spring-web/src/main/java/org/springframework/web/service/invoker/HttpServiceProxyFactory.java index 8c1d9a90cb48..51bb1e285b7b 100644 --- a/spring-web/src/main/java/org/springframework/web/service/invoker/HttpServiceProxyFactory.java +++ b/spring-web/src/main/java/org/springframework/web/service/invoker/HttpServiceProxyFactory.java @@ -66,13 +66,14 @@ public final class HttpServiceProxyFactory { private final ReactiveAdapterRegistry reactiveAdapterRegistry; + @Nullable private final Duration blockTimeout; private HttpServiceProxyFactory( HttpClientAdapter clientAdapter, List argumentResolvers, @Nullable StringValueResolver embeddedValueResolver, - ReactiveAdapterRegistry reactiveAdapterRegistry, Duration blockTimeout) { + ReactiveAdapterRegistry reactiveAdapterRegistry, @Nullable Duration blockTimeout) { this.clientAdapter = clientAdapter; this.argumentResolvers = argumentResolvers; @@ -208,7 +209,8 @@ public Builder reactiveAdapterRegistry(ReactiveAdapterRegistry registry) { /** * Configure how long to wait for a response for an HTTP service method * with a synchronous (blocking) method signature. - *

By default this is 5 seconds. + *

By default this is {@code null}, + * in which case means blocking on publishers is done without a timeout. * @param blockTimeout the timeout value * @return this same builder instance */ @@ -226,7 +228,7 @@ public HttpServiceProxyFactory build() { return new HttpServiceProxyFactory( this.clientAdapter, initArgumentResolvers(), this.embeddedValueResolver, this.reactiveAdapterRegistry, - (this.blockTimeout != null ? this.blockTimeout : Duration.ofSeconds(5))); + this.blockTimeout); } private List initArgumentResolvers() {