Repository navigation
refactor(client): speak WebSocket through HttpClient instead of a hand-rolled framer - #193
Conversation
Pinned exactly: 5.7 is a beta, so an upgrade must be a deliberate edit.
…d-rolled framer sqld answers the upgrade with a 101 that carries content-length: 31 and no body, which the JDK client waits on forever. HttpClient treats a 101 as informational, so it upgrades without a body and the custom RFC 6455 framing can go. The request_id matching, stream ids, blocking call semantics, and SQLITE_BUSY handling stay in the client. permessage-deflate is off so the wire bytes do not change.
A TLS terminator in front of sqld exercises the real handshake, so the wss path is no longer untested. Table names carry the scheme because both runs share one sqld instance.
Independent verification — VERDICT: FAILVerified head What I ranThe Diff checks: no Probes (all via plain JDBC against
|
…eactor that stays up initiateShutdown() only asks the reactor to stop; the executor and connection pool keep running, so awaitShutdown() burned its full timeout and left three threads per connection behind. Closing the client stops the reactor, the executor, and the pool in one step, so connection close returns in single-digit milliseconds again. A decode failure now closes the socket, as the hand-rolled transport did.
Re-verification — VERDICT: PASS+NOTESVerified head The regression I reported is gone: close latency is back to single-digit milliseconds, the three-threads-per-connection leak is gone, rollback-on-close still works, and the close frame still goes out. Regression, before → after (same probes, same server, fresh builds)
Commands runProbe classpath was rebuilt from ProbesClose latency / thread count ( (The transient Does close still send a close frame? A logging TCP proxy between driver and sqld ( So Close mid-transaction, close twice, close idle ( Uncommitted work is rolled back, a second Close after the server is gone ( Large messages (unchanged, re-run on this build): Notes (non-blocking)
No code changes, commits, or pushes; probes live in |
Replace the hand-rolled RFC 6455 transport inside
LibsqlWebSocketClientwith ApacheHttpClient's
httpclient5-websocketmodule. The WebSocket transport now reuses a librarythat already does framing, handshake, TLS, and fragmentation, and about 380 lines of that
code leave the client.
Fixes #192.
Why
sqld answers the upgrade with a
101that carriescontent-length: 31and no body, so theJDK client's
java.net.http.WebSocketnever finishes its opening handshake. #190 shipped ahand-written framer to work around that. HttpClient treats a
101as informational andupgrades without reading a body, so the workaround is no longer needed.
What changes
libsql-clientdepends onhttpclient5-websocket5.7-beta1, pinned in the root pom.LibsqlWebSocketClientkeeps itsrequest_idmatching, stream ids, and blocking callsemantics on top of the library.
Transportinner class, the static handshake, the frame encoder and decoder, theaccept-key computation, and the socket and
SSLSocketsetup are deleted.lifetime stay what the hand-rolled transport gave: single-digit milliseconds and no
leftover IO threads.
ws://andwss://. The wsspath goes through an nginx TLS terminator in front of sqld with a self-signed localhost
certificate that the failsafe JVM trusts.
Scope
wsandwss. No Hrana message, JDBC API, or HTTP transportchange.
permessage-deflateis off, so the bytes on the wire stay what they were.Tradeoffs
httpclient5,httpcore5,httpcore5-h2,httpclient5-cache,and
slf4j-apiintolibsql-client. An application with no SLF4J binding gets SLF4J'sone-time "no providers" notice on stderr.
Blast Radius
Every
jdbc:libsql:ws://andwss://connection changes transport. The HTTP transport,the codec, and the JDBC layer are untouched, and their suites still pass. The hidden cost
is dependency footprint for anyone who only uses
http://URLs but resolves the clientmodule's transitive dependencies.
Verification
./mvnw spotless:checkpasses, and./mvnw testpasses (374 JDBC tests, 35 codec tests).WebSocketTransportITandWebSocketProtobufTransportITrun 15 cases acrossws://andwss://againstghcr.io/tursodatabase/libsql-server:v0.24.33and pass.mvn clean verifypasses locally, including the HTTP integration tests, the Hikari poolchurn test, the toxiproxy test, and the conformance suite.