Skip to content

WebSocketTransport.connect drops inbound frames that arrive before futureSocket is published #42

@nficano

Description

@nficano

In arcp-client/src/main/java/dev/arcp/client/WebSocketTransport.java the connect static factory around line 50 creates the WebSocket listener and starts the buildAsync call, then waits for the buildAsync future to complete, then constructs the WebSocketTransport wrapper, and only afterward calls futureSocket.set(transport) around line 108. The listener body inside buildAsync references futureSocket.get() for every onText, onClose, and onError event — and the listener may begin firing immediately after onOpen runs and requests a frame. If the server sends an envelope before the assembly completes and the AtomicReference is published, futureSocket.get() returns null, the onText handler silently drops the frame, and the envelope is lost. The same null check makes onClose and onError silently no-op during the same window. With a fast-handshaking server (especially the in-process MemoryTransport or a local Jetty), the first session.welcome envelope can be the one that gets dropped, leaving the client hanging on connect().get(...) forever.\n\nFix prompt: Refactor arcp-client/src/main/java/dev/arcp/client/WebSocketTransport.java connect so that the WebSocketTransport instance is constructed before builder.buildAsync is invoked, and the listener captures that instance directly via final reference instead of through an AtomicReference holder. Because the WebSocketTransport currently requires the WebSocket itself in its constructor, change the field private final WebSocket socket to non-final and add a package-private attachSocket(WebSocket) setter that runs once after buildAsync completes; meanwhile buffer inbound frames into the SubmissionPublisher whether or not the socket has been attached (the listener never needs the WebSocket reference for read, only for write). For send safety, gate send(Envelope) on the socket being attached (throw IllegalStateException with a clear message if called pre-attach). Add a regression test using a stub WebSocketListener that fires onOpen + onText immediately and asserts the inbound publisher receives the frame even when delivery beats the buildAsync future resolution.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingseverity:highHigh severity

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions