-
Notifications
You must be signed in to change notification settings - Fork 38.3k
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
WebFlux SSE controller does not detect disconnected client [SPR-15306] #18523
Comments
Rossen Stoyanchev commented I haven't confirmed but I suspect the issue is due to a limitation in the Servlet async API (SERVLET_SPEC-44). To confirm you can try switching to any of the supported non-Servlet runtimes like Reactor Netty, RxNetty, or Undertow. It may be possible to address this specifically when running on Tomcat (I will follow up on that). Beyond that I just raised the question on the Servlet 4 mailing list to see if there is any chance of this being addressed. |
Sergei Egorov commented I tried Reactor Netty, but it didn't help |
Rossen Stoyanchev commented Are you sure you had Tomcat successfully swapped out for Reactor Netty? At present Boot 2 snapshots default to Reactor Netty. I started from start.spring.io and used curl from the command line. After Ctrl+C from curl, the cancel signal appeared immediately:
Then I switched to Tomcat and got the issue you described. It kept logging until it timed out (no cancel signal):
|
Sergei Egorov commented ReactiveWebServerConfiguration.ReactorNettyAutoConfiguration matched:
...
ReactiveWebServerConfiguration.TomcatAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required class 'org.apache.catalina.startup.Tomcat' (OnClassCondition) I run the same script I linked, after full cache cleanup to ensure that I'm using the latest Snapshot. However, I see logs after I pressed "Ctrl-C", and no "cancel" event at all |
Rossen Stoyanchev commented Hm, very strange. I'm not sure why but I see different behavior. Can you do |
Sergei Egorov commented I wasn't using Gradle, but just I'll try fresh demo project from start.spring.io now |
Sergei Egorov commented Reproduced. |
Sergei Egorov commented wrote a test. Nobody can argue with a test :D |
Rossen Stoyanchev commented Not questioning what you're seeing. Just trying to figure out why the difference. I still see expected behavior from the server side if I use curl. The test you provided with the WebClient (and StepVerifier) however does demonstrate what you described. At this point I suspect it's related to the WebClient or our Reactory Netty client connector not seeing or not processing the cancel. |
Rossen Stoyanchev commented There is at least one issue to be fixed on the Reactor Netty side reactor/reactor-netty#57. Beyond there may be more work left . On my machine (Linux) Netty is using native epolling and doesn't have trouble detecting the connection closing from the sever side. When epolling is turned off however, it seems to wait for the next write which in this case never comes. |
Sergei Egorov commented Cool! I use Mac so it explains why we're getting different results. Thanks for the explanation! |
Rossen Stoyanchev commented There were a couple of fixes in reactor-netty 0.6.2 that address this issue. I've confirmed with both epoll and nio loop. If you could please give it a try. Just change the reactor-netty version to 0.6.2.RELEASE. |
Rossen Stoyanchev commented Resolving for now since this should work with Reactor Netty 0.6.2. It would be great to get a confirmation from your side. Thanks for the report. |
I seem to be seeing this issue on my set up. In my case I am hooked up to a docker daemon wrapped in a socat to forward TCP to unix socket. My relevant dependencies are
|
You've see the first paragraph here? |
@rstoyanchev so you're making the assumption that one has control of the server side which some of us do not have access to do so. As such this is not really resolved. |
What you mean by "control of the server side", control of the actual server (runtime) and/or the application that runs (e.g. controllers)? If the controller are part of your application, then the point is that you should be writing an empty SSE periodically. If you don't have control of neither, then it's the concern of whoever does have control. |
Sergei Egorov opened SPR-15306 and commented
Spring SSE implementation doesn't cancel the subscription when the client disconnects but waits until the next failed emission.
It leads to a huge number of open subscriptions when notification rarely happens (i.e. Stocks SSE endpoint with a non-frequently changing stock value).
Reference URL contains a Gist with Groovy app demonstrating an issue.
Start an app, use "curl -v localhost:8080", "CTRL-C". The app will continue to log because "distinctUntilChanged()" doesn't trigger anything, but the subscription is not canceled�.
Critical because if subscription is not lightweight (i.e. polling, or distributed event listening, pub/sub) server's performance quickly goes down and can be DoS'ed by hitting SSE endpoint
Affects: 5.0 M5
Reference URL: https://gist.github.com/bsideup/c69cd2395996adb246639eef43098343
Issue Links:
The text was updated successfully, but these errors were encountered: