Kotlin JS - ktor websocket client loses connection, and doesn't seem to ping

Hi all,

I’m writing a client web app with Kotlin JS and have used various web examples to cobble together a websocket connection with the ktor client.

fun start() {
    val client = HttpClient(Js) {
        install(WebSockets) {
            pingInterval = 1000
        }
    }

    val job = launch {
        client.webSocket(
            request = {
                this.method = HttpMethod.Get
                url(
                    "wss",
                    hostname,
                    443,
                    "/gameSocket/$gameID"
                )
                { }
            },
            block = {
                while (true) {
                    incoming.tryReceive().onSuccess { frame ->
                        (frame as? Frame.Binary)?.data?.decodeToString()?.let gotData@{ jsonString ->
                            try {
                                handleJsonString(jsonString)
                                return@gotData
                            } catch(e: Throwable) {
                                console.error("Unexpected data: $e")
                            }
                        }
                    }

                    outgoingFrames.removeFirstOrNull()?.let {
                        console.log("Sending frame")
                        send(it)
                    }

                    delay(100)
                }
            }
        )
    }

    job.invokeOnCompletion { cause ->
        console.log("Job completed ($cause)")
        client.close()
    }
}

My testing used a local server, with a ws scheme on port 8080, and socket connections worked fine and lived essentially forever. I knew I’d have to write some more handling around this when I moved onto the web proper, but I feel a bit like I’m falling at the first hurdle.

60 seconds after this method is invoked, the connection is lost, but none of this code is notified (I’ve also tried wrapping the whole content of the launched coroutine in a try-catch but no Throwable propagated that far). I get two messages in the browser console:

  • WebSocket connection to ‘$MY_URL’ failed: The network connection was lost.
  • IllegalStateException: Already resumed, but proposed with update CompletedExceptionally[WebSocketException: {“target”:0,“type”:“error” “isTrusted”:true}]

The consistent 60 seconds smells like my nginx instance shutting down an idle connection to me, and my current line of investigation is into how to make the ktor client ping every now and again (setting the pingInterval is apparently insufficient).

But if anyone has any guidance at all on how to more effectively debug the source of the connection loss or the exception, and whether there’s code I’m missing to detect a connection failure so that I can reconnect, I’d appreciate the help. I am at a loss right now.

Thanks!

For anyone who comes here with a similar problem, further reading suggests that, at time of writing, support may not exist for Ping/Pong in JS Websockets on any platform. I’ve implemented a keep-alive of my own and it seems to fix the problem.

I’ll update this further if anything else of note happens.

1 Like