Skip to content
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

WebSocket is not closed after calling session#close [SPR-17277] #21810

Closed
spring-projects-issues opened this issue Sep 16, 2018 · 1 comment
Closed
Assignees
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) status: invalid An issue that we don't feel is valid

Comments

@spring-projects-issues
Copy link
Collaborator

spring-projects-issues commented Sep 16, 2018

Sola opened SPR-17277 and commented

following is reproducible code

package com.example.demo

import org.assertj.core.api.Assertions
import org.junit.Test
import org.junit.runner.RunWith
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.web.server.LocalServerPort
import org.springframework.context.annotation.Bean
import org.springframework.test.context.junit4.SpringRunner
import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping
import org.springframework.web.reactive.socket.WebSocketHandler
import org.springframework.web.reactive.socket.WebSocketMessage
import org.springframework.web.reactive.socket.WebSocketSession
import org.springframework.web.reactive.socket.client.ReactorNettyWebSocketClient
import org.springframework.web.reactive.socket.server.support.WebSocketHandlerAdapter
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono
import java.net.URI
import java.util.*
import java.util.concurrent.atomic.AtomicInteger

/**
 * @author Sola
 */
@RunWith(SpringRunner::class)
@SpringBootTest(
    webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
    classes = [WebSocketCloseTest.TestApplication::class]
)
class WebSocketCloseTest {

    @SpringBootApplication
    class TestApplication {

        @Bean
        fun handlerMapping() = SimpleUrlHandlerMapping().apply {
            val map = HashMap<String, WebSocketHandler>()
            map["/test/echo"] =
                    EchoHandler()

            val mapping = SimpleUrlHandlerMapping()
            mapping.urlMap = map
            mapping.order = -1 // before annotated controllers
            return mapping
        }

        @Bean
        fun handlerAdapter() = WebSocketHandlerAdapter()

        class EchoHandler : WebSocketHandler {

            override fun handle(session: WebSocketSession): Mono<Void> {
                return session.send(
                    session.receive().filter {
                        it.type == WebSocketMessage.Type.TEXT
                    }.map {
                        val payloadAsText = it.payloadAsText
                        println("Server Received: $payloadAsText")
                        session.textMessage(payloadAsText)
                    }.doOnTerminate {
                        println("Client Closed!")
                    }
                )
            }

        }

    }

    private val ws = ReactorNettyWebSocketClient()

    @LocalServerPort
    private var port: Int = 0

    @Test
    fun `web socket should work as expected`() {
        ws.execute(URI("ws://localhost:$port/test/echo")) { session ->
            val output = Flux.range(1, 10).map { session.textMessage(it.toString()) }
            val count = AtomicInteger(1)
            val input = session.receive().take(10).flatMap {
                val text = it.payloadAsText
                Assertions.assertThat(count.getAndIncrement()).isEqualTo(text.toInt())
                Mono.empty<WebSocketMessage>()
            }
            session.send(output.mergeWith(input)).doOnTerminate {
                println("END!")
                session.close()
            }
        }.block()
        readLine()
    }

}

What is expected: The "Client Closed" message should be printed on stdout.


Affects: 5.0.9

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Sep 17, 2018

Brian Clozel commented

Your session.close() call is done within a doOnTerminate operator, which is a side-effect operator.

This operation, which returns a Mono<Void> is not part of any reactive chain, so nothing subscribes to it - the client will never close the session.

For future questions, please use StackOverflow. Thanks!

@spring-projects-issues spring-projects-issues added type: bug A general bug status: invalid An issue that we don't feel is valid in: web Issues in web modules (web, webmvc, webflux, websocket) labels Jan 11, 2019
@spring-projects-issues spring-projects-issues removed the type: bug A general bug label Jan 12, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) status: invalid An issue that we don't feel is valid
Projects
None yet
Development

No branches or pull requests

2 participants