Docs

Documentation versions (currently viewingVaadin 24)

Sync Server & Client UI States

Technical details of how server to client communications work.

Server to client communications contain the synchronization tokens for communicating and UI state tracking. This tracking is meant for ordering messages. It’s also used to verify that both sides are in the same known state.

Synchronization Tokens

The syncId token marks the state of the server and is returned as received by the client. Whereas, the clientId token is incremented for each message sent by the client, with the server incrementing to match the next id in the response. Both syncId and clientId are integers.

syncId

The syncId holds the latest communication state identifier given by the server. It’s generated as a strictly increasing id for each response to every request from the client.

This identifier is replayed to the server on each request from the client. It helps the server to know the state of the client and to compare it against its own state.

The initial value when no response has been received from the server is UNDEFINED_SYNC_ID(-1). This is the value after the bootstrap HTML loading and before the first UI is rendered.

The syncId is always incremented by 1 after a new UIDL response is generated. The client then handles the received messages according to the syncId and the latest handled syncId, so that changes are handled in the correct order.

clientId

The clientId holds the latest communication state identifier given by the client. The client token is incremented on the client after sending the message. The server increments the value in the response to match the next expected clientId (i.e., client updated after message sent).

On the client, pending messages are removed from the queue as handled when clientId from server matches the next expected value. If the id is less than expected, the client waits since the server has not yet seen all messages. The response should arrive later. Otherwise, the client trusts the server and updates the id to the server’s expectations.

On the server, in cases where the id is the previous one with the same request payload, the server re-sends the latest response since the client probably didn’t receive the message. If the client-sent id doesn’t match the server-expected id, a re-synchronization is initiated.

UI State Re-Synchronization

Re-synchronization occurs when the client detects that its state is no longer in sync with the server. This can happen due to unexpected network interruptions, or inconsistencies between the client-side UI and server-side state caused by misconfigured reverse proxies or session replication setups.

Several factors can lead to message loss or unexpected message identifiers:

  • Incorrect load balancer or reverse proxy configuration: Using setups without sticky sessions may result in receiving messages from the server which were meant for a different session or UI.

  • Firewall or Virtual Private Network (VPN) interference: Deep packet inspection can block certain packets.

These factors might also generate a delay in arrival of the messages. Virus scanners are particularly problematic and may cause issues when WebSocket_XHR is used. Increasing the maxMessageSuspendTimeout parameter value could help mitigate message arrival delays.

Other potential causes include:

  • Faulty router hardware: This could be due to routers using outdated firmware versions.

  • Unstable Wi-Fi or cellular connections: Fluctuating network conditions can disrupt communication.

  • Server-side issues: Request-handling hiccups may lead to inconsistencies, possibly due to server performance degradation.

Re-Synchronization Initiation & Mechanism

Re-synchronization is initiated by the client when it can’t find a message with the expected syncId among the pending messages from the server within a given timeout. The default is 5 seconds, which is configurable using the maxMessageSuspendTimeout parameter. Below is the process followed to re-synchronize:

Client Initiation:

  • The client clears the queue of pending messages from the server.

  • It terminates the current request and sends a re-synchronization request to the server.

Server Handling:

  • Upon receiving the re-synchronization request, the server invokes the detached listeners of UI components and re-attaches all components to the state tree.

  • The server then sends a response that includes the current UI state needed to rebuild the client-side state tree.

Client Update:

  • The client receives the updated UI state from the server.

  • It clears all old pending messages, updates the last known syncId to the newly received value, and rebuilds the DOM tree from scratch based on the server’s current state.

This process ensures UI consistency, even in the presence of errors or unexpected behavior. The application remains robust against transient network problems or client-side interruptions. Additionally, the user experience is preserved without requiring a full page reload, as Vaadin rebuilds the UI without reloading the entire bundle from the server.