Skip to content

Commit 70a3dbf

Browse files
committed
WebSession creation does not block
Closes gh-24027
1 parent ddb38ee commit 70a3dbf

File tree

3 files changed

+31
-11
lines changed

3 files changed

+31
-11
lines changed

spring-web/src/main/java/org/springframework/web/server/session/InMemoryWebSessionStore.java

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -29,6 +29,7 @@
2929
import java.util.concurrent.locks.ReentrantLock;
3030

3131
import reactor.core.publisher.Mono;
32+
import reactor.core.scheduler.Schedulers;
3233

3334
import org.springframework.util.Assert;
3435
import org.springframework.util.IdGenerator;
@@ -111,9 +112,14 @@ public Map<String, WebSession> getSessions() {
111112

112113
@Override
113114
public Mono<WebSession> createWebSession() {
115+
116+
// Opportunity to clean expired sessions
114117
Instant now = this.clock.instant();
115118
this.expiredSessionChecker.checkIfNecessary(now);
116-
return Mono.fromSupplier(() -> new InMemoryWebSession(now));
119+
120+
return Mono.fromSupplier(() -> new InMemoryWebSession(now))
121+
.subscribeOn(Schedulers.boundedElastic())
122+
.cast(WebSession.class);
117123
}
118124

119125
@Override

spring-web/src/test/java/org/springframework/web/server/session/InMemoryWebSessionStoreTests.java

+11
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@
2222
import java.util.Map;
2323
import java.util.stream.IntStream;
2424

25+
import org.junit.jupiter.api.Disabled;
2526
import org.junit.jupiter.api.Test;
27+
import reactor.core.publisher.Mono;
28+
import reactor.core.scheduler.Schedulers;
2629

2730
import org.springframework.beans.DirectFieldAccessor;
2831
import org.springframework.web.server.WebSession;
@@ -56,6 +59,14 @@ public void startsSessionImplicitly() {
5659
assertThat(session.isStarted()).isTrue();
5760
}
5861

62+
@Disabled // TODO: remove if/when Blockhound is enabled
63+
@Test // gh-24027
64+
public void createSessionDoesNotBlock() {
65+
Mono.defer(() -> this.store.createWebSession())
66+
.subscribeOn(Schedulers.parallel())
67+
.block();
68+
}
69+
5970
@Test
6071
public void retrieveExpiredSession() {
6172
WebSession session = this.store.createWebSession().block();

spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ModelInitializerTests.java

+12-9
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@
6464
*/
6565
public class ModelInitializerTests {
6666

67+
private static final Duration TIMEOUT = Duration.ofMillis(5000);
68+
69+
6770
private ModelInitializer modelInitializer;
6871

6972
private final ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/path"));
@@ -93,7 +96,7 @@ public void initBinderMethod() {
9396

9497
Method method = ResolvableMethod.on(TestController.class).annotPresent(GetMapping.class).resolveMethod();
9598
HandlerMethod handlerMethod = new HandlerMethod(controller, method);
96-
this.modelInitializer.initModel(handlerMethod, context, this.exchange).block(Duration.ofMillis(5000));
99+
this.modelInitializer.initModel(handlerMethod, context, this.exchange).block(TIMEOUT);
97100

98101
WebExchangeDataBinder binder = context.createDataBinder(this.exchange, "name");
99102
assertThat(binder.getValidators()).isEqualTo(Collections.singletonList(validator));
@@ -107,7 +110,7 @@ public void modelAttributeMethods() {
107110

108111
Method method = ResolvableMethod.on(TestController.class).annotPresent(GetMapping.class).resolveMethod();
109112
HandlerMethod handlerMethod = new HandlerMethod(controller, method);
110-
this.modelInitializer.initModel(handlerMethod, context, this.exchange).block(Duration.ofMillis(5000));
113+
this.modelInitializer.initModel(handlerMethod, context, this.exchange).block(TIMEOUT);
111114

112115
Map<String, Object> model = context.getModel().asMap();
113116
assertThat(model.size()).isEqualTo(5);
@@ -116,7 +119,7 @@ public void modelAttributeMethods() {
116119
assertThat(((TestBean) value).getName()).isEqualTo("Bean");
117120

118121
value = model.get("monoBean");
119-
assertThat(((Mono<TestBean>) value).block(Duration.ofMillis(5000)).getName()).isEqualTo("Mono Bean");
122+
assertThat(((Mono<TestBean>) value).block(TIMEOUT).getName()).isEqualTo("Mono Bean");
120123

121124
value = model.get("singleBean");
122125
assertThat(((Single<TestBean>) value).toBlocking().value().getName()).isEqualTo("Single Bean");
@@ -135,7 +138,7 @@ public void saveModelAttributeToSession() {
135138

136139
Method method = ResolvableMethod.on(TestController.class).annotPresent(GetMapping.class).resolveMethod();
137140
HandlerMethod handlerMethod = new HandlerMethod(controller, method);
138-
this.modelInitializer.initModel(handlerMethod, context, this.exchange).block(Duration.ofMillis(5000));
141+
this.modelInitializer.initModel(handlerMethod, context, this.exchange).block(TIMEOUT);
139142

140143
WebSession session = this.exchange.getSession().block(Duration.ZERO);
141144
assertThat(session).isNotNull();
@@ -148,7 +151,7 @@ public void saveModelAttributeToSession() {
148151

149152
@Test
150153
public void retrieveModelAttributeFromSession() {
151-
WebSession session = this.exchange.getSession().block(Duration.ZERO);
154+
WebSession session = this.exchange.getSession().block(TIMEOUT);
152155
assertThat(session).isNotNull();
153156

154157
TestBean testBean = new TestBean("Session Bean");
@@ -159,7 +162,7 @@ public void retrieveModelAttributeFromSession() {
159162

160163
Method method = ResolvableMethod.on(TestController.class).annotPresent(GetMapping.class).resolveMethod();
161164
HandlerMethod handlerMethod = new HandlerMethod(controller, method);
162-
this.modelInitializer.initModel(handlerMethod, context, this.exchange).block(Duration.ofMillis(5000));
165+
this.modelInitializer.initModel(handlerMethod, context, this.exchange).block(TIMEOUT);
163166

164167
context.saveModel();
165168
assertThat(session.getAttributes().size()).isEqualTo(1);
@@ -174,13 +177,13 @@ public void requiredSessionAttributeMissing() {
174177
Method method = ResolvableMethod.on(TestController.class).annotPresent(PostMapping.class).resolveMethod();
175178
HandlerMethod handlerMethod = new HandlerMethod(controller, method);
176179
assertThatIllegalArgumentException().isThrownBy(() ->
177-
this.modelInitializer.initModel(handlerMethod, context, this.exchange).block(Duration.ofMillis(5000)))
180+
this.modelInitializer.initModel(handlerMethod, context, this.exchange).block(TIMEOUT))
178181
.withMessage("Required attribute 'missing-bean' is missing.");
179182
}
180183

181184
@Test
182185
public void clearModelAttributeFromSession() {
183-
WebSession session = this.exchange.getSession().block(Duration.ZERO);
186+
WebSession session = this.exchange.getSession().block(TIMEOUT);
184187
assertThat(session).isNotNull();
185188

186189
TestBean testBean = new TestBean("Session Bean");
@@ -191,7 +194,7 @@ public void clearModelAttributeFromSession() {
191194

192195
Method method = ResolvableMethod.on(TestController.class).annotPresent(GetMapping.class).resolveMethod();
193196
HandlerMethod handlerMethod = new HandlerMethod(controller, method);
194-
this.modelInitializer.initModel(handlerMethod, context, this.exchange).block(Duration.ofMillis(5000));
197+
this.modelInitializer.initModel(handlerMethod, context, this.exchange).block(TIMEOUT);
195198

196199
context.getSessionStatus().setComplete();
197200
context.saveModel();

0 commit comments

Comments
 (0)