Hello,
websockets with webflux don't work on native-image. I'm using this code to create a websocket. This works on JVM in AOT mode, but fails in native-image with:
2022-08-03T15:41:22.605+02:00 ERROR 32880 --- [ctor-http-nio-3] a.w.r.e.AbstractErrorWebExceptionHandler : [d4196bb1-5] 500 Server Error for HTTP GET "/ws/count"
java.lang.IllegalStateException: No suitable RequestUpgradeStrategy
at org.springframework.web.reactive.config.WebFluxConfigurationSupport$NoUpgradeStrategyWebSocketService.handleRequest(WebFluxConfigurationSupport.java:553) ~[na:na]
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
*__checkpoint ⇢ HTTP GET "/ws/count" [ExceptionHandlingWebHandler]
Original Stack Trace:
at org.springframework.web.reactive.config.WebFluxConfigurationSupport$NoUpgradeStrategyWebSocketService.handleRequest(WebFluxConfigurationSupport.java:553) ~[na:na]
at org.springframework.web.reactive.socket.server.support.WebSocketHandlerAdapter.handle(WebSocketHandlerAdapter.java:107) ~[webflux-netty:6.0.0-SNAPSHOT]
at org.springframework.web.reactive.DispatcherHandler.invokeHandler(DispatcherHandler.java:171) ~[webflux-netty:6.0.0-SNAPSHOT]
at org.springframework.web.reactive.DispatcherHandler.lambda$handle$1(DispatcherHandler.java:153) ~[webflux-netty:6.0.0-SNAPSHOT]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:125) ~[webflux-netty:3.5.0-M4]
at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:74) ~[na:na]
at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:82) ~[webflux-netty:3.5.0-M4]
at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.innerNext(FluxConcatMapNoPrefetch.java:258) ~[webflux-netty:3.5.0-M4]
at reactor.core.publisher.FluxConcatMap$ConcatMapInner.onNext(FluxConcatMap.java:863) ~[na:na]
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:129) ~[na:na]
at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2398) ~[webflux-netty:3.5.0-M4]
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.request(FluxMapFuseable.java:171) ~[na:na]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.request(Operators.java:2158) ~[webflux-netty:3.5.0-M4]
at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.request(FluxConcatMapNoPrefetch.java:338) ~[webflux-netty:3.5.0-M4]
at reactor.core.publisher.MonoNext$NextSubscriber.request(MonoNext.java:108) ~[webflux-netty:3.5.0-M4]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:2194) ~[webflux-netty:3.5.0-M4]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onSubscribe(Operators.java:2068) ~[webflux-netty:3.5.0-M4]
at reactor.core.publisher.MonoNext$NextSubscriber.onSubscribe(MonoNext.java:70) ~[webflux-netty:3.5.0-M4]
at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.onSubscribe(FluxConcatMapNoPrefetch.java:164) ~[webflux-netty:3.5.0-M4]
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:165) ~[na:na]
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:87) ~[na:na]
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) ~[webflux-netty:3.5.0-M4]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52) ~[na:na]
at reactor.core.publisher.Mono.subscribe(Mono.java:4321) ~[webflux-netty:3.5.0-M4]
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:263) ~[webflux-netty:3.5.0-M4]
at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:51) ~[na:na]
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) ~[webflux-netty:3.5.0-M4]
at reactor.core.publisher.MonoDeferContextual.subscribe(MonoDeferContextual.java:55) ~[na:na]
at reactor.netty.http.server.HttpServer$HttpServerHandle.onStateChange(HttpServer.java:967) ~[na:na]
at reactor.netty.ReactorNetty$CompositeConnectionObserver.onStateChange(ReactorNetty.java:677) ~[na:na]
at reactor.netty.transport.ServerTransport$ChildObserver.onStateChange(ServerTransport.java:478) ~[na:na]
at reactor.netty.http.server.HttpServerOperations.onInboundNext(HttpServerOperations.java:570) ~[webflux-netty:1.1.0-M4]
at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:93) ~[na:na]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[webflux-netty:4.1.79.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[webflux-netty:4.1.79.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[webflux-netty:4.1.79.Final]
at reactor.netty.http.server.HttpTrafficHandler.channelRead(HttpTrafficHandler.java:222) ~[na:na]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[webflux-netty:4.1.79.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[webflux-netty:4.1.79.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[webflux-netty:4.1.79.Final]
at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436) ~[webflux-netty:4.1.79.Final]
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:327) ~[webflux-netty:4.1.79.Final]
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:299) ~[webflux-netty:4.1.79.Final]
at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251) ~[webflux-netty:4.1.79.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[webflux-netty:4.1.79.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[webflux-netty:4.1.79.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[webflux-netty:4.1.79.Final]
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) ~[na:na]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[webflux-netty:4.1.79.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[webflux-netty:4.1.79.Final]
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) ~[webflux-netty:4.1.79.Final]
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166) ~[webflux-netty:4.1.79.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:722) ~[na:na]
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:658) ~[na:na]
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:584) ~[na:na]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:496) ~[na:na]
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) ~[na:na]
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[na:na]
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[na:na]
at java.lang.Thread.run(Thread.java:833) ~[webflux-netty:na]
at com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:704) ~[webflux-netty:na]
at com.oracle.svm.core.posix.thread.PosixPlatformThreads.pthreadStartRoutine(PosixPlatformThreads.java:202) ~[na:na]
Comment From: sdeleuze
webflux-netty
AOT smoke test has a websocket test and is currently green on the CI, https://github.com/spring-projects/spring-boot/issues/33347 mentions that WebSocket works on Netty, Tomcat and Undertow. Only Jetty WebSocket support seems broken and that's probably not something we should handle on Framework side, so I will close this issue.