I’m using Ktor 3.0 to connect to the OpenAI Realti...
# ktor
c
I’m using Ktor 3.0 to connect to the OpenAI Realtime API with websockets. When I hit a rate limit, how am I supposed to catch that and recover? It doesn’t seem like wrapping
sendSerialized()
with a try-catch works. I’ll share the exception I see in a thread.
Copy code
Exception in thread "AWT-EventQueue-0" java.net.http.WebSocketHandshakeException
	at java.net.http/jdk.internal.net.http.websocket.OpeningHandshake.resultFrom(OpeningHandshake.java:224)
	at java.base/java.util.concurrent.CompletableFuture$UniCompose.tryFire(CompletableFuture.java:1150)
	at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510)
	at java.base/java.util.concurrent.CompletableFuture.postFire(CompletableFuture.java:614)
	at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:844)
	at java.base/java.util.concurrent.CompletableFuture$Completion.exec(CompletableFuture.java:483)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:387)
	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1312)
	at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1843)
	at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1808)
	at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:188)
	Suppressed: kotlin.UninitializedPropertyAccessException: lateinit property webSocket has not been initialized
		at io.ktor.client.engine.java.JavaHttpWebSocket$2.invokeSuspend(JavaHttpWebSocket.kt:122)
		at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
		at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:99)
		at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:113)
		at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:89)
		at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:589)
		at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:823)
		at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:720)
		at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:707)
	Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@15bc4223, Dispatchers.Main.immediate]
Caused by: jdk.internal.net.http.websocket.CheckFailedException: Unexpected HTTP response status code 429
	at java.net.http/jdk.internal.net.http.websocket.OpeningHandshake.checkFailed(OpeningHandshake.java:341)
	at java.net.http/jdk.internal.net.http.websocket.OpeningHandshake.handleResponse(OpeningHandshake.java:250)
	at java.net.http/jdk.internal.net.http.websocket.OpeningHandshake.resultFrom(OpeningHandshake.java:220)
	... 10 more
a
Can you describe how the WebSocket server behaves when you hit the rate limit?
c
Is what way? I don’t control the server, but it seems like it is responding with a 429 when initially opening the socket.
a
So, does it only happen on connection establishment?
c
In the stacktrace above, that’s when I was hitting it. If it matters, I’m doing
Copy code
val connection = httpClient.webSocketSession { ... }
so that the connection can be long-lived with interactions from the rest of the application. I don’t think I tried a try-catch surrounding the builder yet.
Maybe one question is when is the connection established with the builder?
a
The
WebSocketHandshakeException
should be possible to catch by wrapping the
webSocketSession
call in the try/catch.
c
Ok, that would probably help in the specific exception I encountered. Maybe a documentation update to
webSocketSession{}
indicating it can throw
WebSocketHandshakeException
could help others figuring out the API?
In the next few days, I’m planning to write some test cases for my client against a
testApplication{}
where I can explicitly control timing of 429s and that should help me figure out how to make this more robust too.
a
There is an open issue (KTOR-2630), which you can follow, to introduce common network exceptions unifying different platform- and engine-specific exceptions.
c
When that issue is resolved it would be quite helpful. Thanks for the link!