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.
Two styles of WebSocket handling
Section titled “Two styles of WebSocket handling”1. Stateless handlers (singleton style)
Section titled “1. Stateless handlers (singleton style)”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());}@HandleSocketOpen("/chat")fun onOpen(): String { return "Welcome!"}
@HandleSocketMessage("/chat")fun onMessage(incoming: String): String { return "Echo: $incoming"}
@HandleSocketClose("/chat")fun onClose(session: SocketSession) { 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
2. Stateful sessions with @SocketEndpoint
Section titled “2. Stateful sessions with @SocketEndpoint”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()); }}@SocketEndpoint@Path("/chat")class ChatSession {
private val messages = mutableListOf<String>()
@HandleSocketOpen fun onOpen(): String { return "Connected!" }
@HandleSocketMessage fun onMessage(text: String, session: SocketSession) { messages += text session.sendMessage("Stored message: $text") }
@HandleSocketClose fun onClose() { 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.
Automatic ping-pong and keep-alive
Section titled “Automatic ping-pong and keep-alive”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
aliveCheckattribute
@SocketEndpoint(aliveCheck = @SocketEndpoint.AliveCheck(pingDelay = 30, pingTimeout = 15))public class MySession { // ...}@SocketEndpoint( aliveCheck = SocketEndpoint.AliveCheck(pingDelay = 30, pingTimeout = 15))class MySession { // ...}Summary
Section titled “Summary”| Annotation | Description |
|---|---|
| @HandleSocketOpen | Handles WebSocket connection opening |
| @HandleSocketMessage | Handles incoming WebSocket messages (text/binary) |
| @HandleSocketPong | Handles pong responses (e.g. from keep-alive) |
| @HandleSocketClose | Handles WebSocket session closure |
| @HandleSocketHandshake | Customizes the initial handshake |
| @SocketEndpoint | Declares a per-session WebSocket handler class |
| SocketSession (injected) | Allows sending messages, pinging, and closing |
Request failures
Section titled “Request failures”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