Skip to content

Handling WebSocket messages

Use WebSockets when a browser and your application need to keep exchanging messages, for example in a chat or live view. A socket handler receives incoming messages and can return a reply using the same handler style as HTTP.

WebSocket requests are published to the WebRequest log after being reverse-forwarded from the Fluxzero Runtime, and can be consumed and responded to like any other request type.


Build a live task screen for a complete example of Model changes reaching a browser.

Use annotations like @HandleSocketOpen, @HandleSocketMessage, and @HandleSocketClose directly on singleton handler classes:

@HandleSocketOpen("/chat")
public String onOpen() {
return "Welcome!";
}
@HandleSocketMessage("/chat")
public String onMessage(String incoming) {
return "Echo: " + incoming;
}
@HandleSocketClose("/chat")
public void onClose(SocketSession session) {
System.out.println("Socket closed: " + session.sessionId());
}

You can return a response directly from onOpen or onMessage. For more control, inject SocketSession and send messages manually.

Other available annotations:

  • @HandleSocketPong — handle pong responses
  • @HandleSocketHandshake — override default handshake logic

Use @SocketEndpoint to create a new handler instance per session, allowing you to store session-local state:

@SocketEndpoint
@Path("/chat")
public class ChatSession {
private final List<String> messages = new ArrayList<>();
@HandleSocketOpen
public String onOpen() {
return "Connected!";
}
@HandleSocketMessage
public void onMessage(String text, SocketSession session) {
messages.add(text);
session.sendMessage("Stored message: " + text);
}
@HandleSocketClose
public void onClose() {
System.out.println("Messages in this session: " + messages.size());
}
}

Stateful sessions are ideal for authentication, accumulating messages, buffering, or managing cursors and sequences.

You can combine @SocketEndpoint with @ServeStatic on the same class. Static files are available independently of socket sessions, including before opening and after closing one. A class/package @Path also contributes to the static mount. Register the endpoint by class and test both HTTP assets and socket lifecycle messages at that prefix; the same rules apply in Java and Kotlin.


Fluxzero automatically manages ping/pong logic for connections handled by @SocketEndpoint:

  • Sends pings at regular intervals (default: every 60 seconds)
  • Closes the session if a pong isn’t received in time
  • Customizable using the aliveCheck attribute
@SocketEndpoint(aliveCheck = @SocketEndpoint.AliveCheck(pingDelay = 30, pingTimeout = 15))
public class MySession {
// ...
}

AnnotationDescription
@HandleSocketOpenHandles WebSocket connection opening
@HandleSocketMessageHandles incoming WebSocket messages (text/binary)
@HandleSocketPongHandles pong responses (e.g. from keep-alive)
@HandleSocketCloseHandles WebSocket session closure
@HandleSocketHandshakeCustomizes the initial handshake
@SocketEndpointDeclares a per-session WebSocket handler class
SocketSession (injected)Allows sending messages, pinging, and closing

For incoming SocketRequest messages, automatic SocketResponse.error replies preserve the request ID. Messages from FunctionalException (including IllegalCommandException) are returned unchanged; other failures use Request failed. This applies to synchronous handlers and handlers returning CompletableFuture, in Java and Kotlin. Use functional exceptions for deliberate caller-facing rejections and keep their text suitable for that caller. Explicitly constructed socket responses remain application-controlled.

Technical failures retain the original cause in an internal log correlated by request ID. Failed-send and unmatched-response logs identify the request without copying its request or response body.


© 2026 Fluxzero