'spring-could-gateway: reactor.netty.channel.AbortedException: Connection has been closed BEFORE send operation
I am getting the following exception in the spring gateway. This exception appears when I have configured Redis Sentinel in the gateway, it throughs exception after a couple of requests in the gateway. If I remove the redis config the gatway is fine.
2022-04-25 15:11:13.475 INFO 1 --- [oundedElastic-8] c.y.c.g.GlobalErrorWebExceptionHandler : Global catch for ex=Connection has been closed BEFORE send operation
2022-04-25 15:11:13.478 ERROR 1 --- [oundedElastic-7] c.y.c.g.GlobalErrorWebExceptionHandler : Unhandled throwable=
reactor.netty.channel.AbortedException: Connection has been closed BEFORE send operation
at reactor.netty.channel.AbortedException.beforeSend(AbortedException.java:59) ~[reactor-netty-core-1.0.17.jar!/:1.0.17]
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
__checkpoint ⇢ Handler org.springframework.boot.actuate.endpoint.web.reactive.AbstractWebFluxEndpointHandlerMapping$ReadOperationHandler#handle(ServerWebExchange) [DispatcherHandler] checkpoint ⇢ com.demo.gateway.config.CorsConfig$$Lambda$1120/0x00000008014c8730 [DefaultWebFilterChain]
*checkpoint ⇢ org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter [DefaultWebFilterChain]
__checkpoint ⇢ org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter [DefaultWebFilterChain] __checkpoint ⇢ HTTP GET "/actuator/health/liveness" [ExceptionHandlingWebHandler]
Original Stack Trace:
at reactor.netty.channel.AbortedException.beforeSend(AbortedException.java:59) ~[reactor-netty-core-1.0.17.jar!/:1.0.17]
at reactor.netty.http.HttpOperations.then(HttpOperations.java:171) ~[reactor-netty-http-1.0.17.jar!/:1.0.17]
at reactor.netty.ReactorNetty$OutboundThen.<init>(ReactorNetty.java:702) ~[reactor-netty-core-1.0.17.jar!/:1.0.17]
at reactor.netty.ReactorNetty$OutboundThen.<init>(ReactorNetty.java:695) ~[reactor-netty-core-1.0.17.jar!/:1.0.17]
at reactor.netty.NettyOutbound.then(NettyOutbound.java:358) ~[reactor-netty-core-1.0.17.jar!/:1.0.17]
at reactor.netty.http.HttpOperations.send(HttpOperations.java:109) ~[reactor-netty-http-1.0.17.jar!/:1.0.17]
at org.springframework.http.server.reactive.ReactorServerHttpResponse.writeWithInternal(ReactorServerHttpResponse.java:92) ~[spring-web-5.3.18.jar!/:5.3.18]
at org.springframework.http.server.reactive.AbstractServerHttpResponse.lambda$null$2(AbstractServerHttpResponse.java:221) ~[spring-web-5.3.18.jar!/:5.3.18]
at org.springframework.http.server.reactive.AbstractServerHttpResponse.doCommit(AbstractServerHttpResponse.java:297) ~[spring-web-5.3.18.jar!/:5.3.18]
at org.springframework.http.server.reactive.AbstractServerHttpResponse.lambda$writeWith$5(AbstractServerHttpResponse.java:218) ~[spring-web-5.3.18.jar!/:5.3.18]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:125) ~[reactor-core-3.4.16.jar!/:3.4.16]
at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onNext(FluxContextWrite.java:107) ~[reactor-core-3.4.16.jar!/:3.4.16]
at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2398) ~[reactor-core-3.4.16.jar!/:3.4.16]
at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.request(FluxContextWrite.java:136) ~[reactor-core-3.4.16.jar!/:3.4.16]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:110) ~[reactor-core-3.4.16.jar!/:3.4.16]
at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onSubscribe(FluxContextWrite.java:101) ~[reactor-core-3.4.16.jar!/:3.4.16]
at reactor.core.publisher.MonoJust.subscribe(MonoJust.java:55) ~[reactor-core-3.4.16.jar!/:3.4.16]
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) ~[reactor-core-3.4.16.jar!/:3.4.16]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:157) ~[reactor-core-> >3.4.16.jar!/:3.4.16]
at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:74) ~[reactor-core-3.4.16.jar!/:3.4.16]
at reactor.core.publisher.Operators$MonoInnerProducerBase.complete(Operators.java:2664) ~[reactor-core-3.4.16.jar!/:3.4.16]
at reactor.core.publisher.MonoSingle$SingleSubscriber.onComplete(MonoSingle.java:180) ~[reactor-core-3.4.16.jar!/:3.4.16]
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onCo
gateway pom dependencies are
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.demo</groupId>
<artifactId>gateway</artifactId>
<version>1.1.1</version>
<name>Gateway</name>
<description>Gateway</description>
<properties>
<java.version>17</java.version>
<spring.cloud-version>2021.0.1</spring.cloud-version>
<modelmapper-spring-boot-starter.version>1.1.0</modelmapper-spring-boot-starter.version>
<io.jsonwebtoken.version>0.11.2</io.jsonwebtoken.version>
<bcpkix-jdk15on.version>1.68</bcpkix-jdk15on.version>
<yc-common-api.version>1.2.6</yc-common-api.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>com.demo</groupId>
<artifactId>yc-common-api</artifactId>
<version>${yc-common-api.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.github.jmnarloch</groupId>
<artifactId>modelmapper-spring-boot-starter</artifactId>
<version>${modelmapper-spring-boot-starter.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>${bcpkix-jdk15on.version}</version>
</dependency>
<!-- JSON WEB Token dependencies -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>${io.jsonwebtoken.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>${io.jsonwebtoken.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>${io.jsonwebtoken.version}</version>
<scope>runtime</scope>
</dependency>
<!-- only required for XML error response of legacy /api/v2/phone/{phone} endpoint -->
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
</dependency>
Redis config class
@Slf4j
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
@Autowired
private RedisProperties redisProperties;
@Bean(name = "redisConnectionFactory")
public RedisConnectionFactory redisConnectionFactory() {
RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration();
sentinelConfig.setMaster(redisProperties.getSentinel().getMaster());
redisProperties.getSentinel().getNodes().forEach(s -> sentinelConfig.sentinel(s, Integer.valueOf(redisProperties.getPort())));
sentinelConfig.setPassword(RedisPassword.of(redisProperties.getPassword()));
GenericObjectPoolConfig<LettuceConnection> genericObjectPoolConfig = new GenericObjectPoolConfig<>();
genericObjectPoolConfig.setMaxIdle(redisProperties.getLettuce().getPool().getMaxIdle());
genericObjectPoolConfig.setMaxTotal(redisProperties.getLettuce().getPool().getMaxActive());
LettucePoolingClientConfiguration poolConfig = LettucePoolingClientConfiguration.builder()
.clientName(redisProperties.getClientName())
.poolConfig(genericObjectPoolConfig)
.clientOptions(ClientOptions.builder()
.socketOptions(SocketOptions.builder().connectTimeout(redisProperties.getTimeout()).build()).build())
.build();
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(sentinelConfig, poolConfig);
connectionFactory.setPipeliningFlushPolicy(PipeliningFlushPolicy.buffered(1000));
connectionFactory.setDatabase(redisProperties.getDatabase());
return connectionFactory;
}
@Bean(name = "cachingRedisTemplate")
public RedisTemplate<String, String> redisTemplate(@Qualifier("redisConnectionFactory") RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, String> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
template.setKeySerializer(new StringRedisSerializer(StandardCharsets.UTF_8));
template.setValueSerializer(new StringRedisSerializer(StandardCharsets.UTF_8));
return template;
}
Redis properties
spring.cache.type=redis
spring.redis.client-name=${spring.application.name}
spring.redis.database=0
spring.redis.password=password
spring.redis.timeout=1000
spring.redis.host=redis.host
spring.redis.port=26379
spring.redis.sentinel.master=mymaster
spring.redis.sentinel.nodes=redis.cluster
spring.redis.sentinel.password=password
spring.redis.lettuce.pool.max-active=30
spring.redis.lettuce.pool.max-idle=30
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|