Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fault-tolerant messaging for server-client communication #20348

Open
7 tasks
mshabarov opened this issue Oct 28, 2024 · 1 comment
Open
7 tasks

Fault-tolerant messaging for server-client communication #20348

mshabarov opened this issue Oct 28, 2024 · 1 comment

Comments

@mshabarov
Copy link
Contributor

mshabarov commented Oct 28, 2024

Describe your motivation

Vaadin doesn't store any information about messages that are sent from server to client (and vice versa) and triggers a full page reload in browser, when the server detect a mismatch between UI state on client and server, e.g. when message is lost.

This may happen due to various reasons, but those caused by network issues / message loose, can be reliably eliminated by implementing two-side message buffer for already sent, but not-yet-confirmed messages. Server can store an ordered log/buffer of UIDL messages and client can store a similar log/buffer for RPC message. The messages are preserved in buffer until a consumer (may be a server or client, depending who sends the message) confirms that it has received the message in the next request, then the producer deletes this message from the buffer.

Describe the solution you'd like

Flow Client (MessageSender) and Flow Server (ServerRPCHandler) have the logs (buffers) of ordered messages that producer (either Flow server for UIDL or Flow client for RPC) has sent to consumer.

These logs has message JSONs mapped to the sync ID or client ID. These IDs are already being used for detecting a out of sync.

Producer stores a message in the log until it gets a confirmation from the consumer.
Once a consumer sends another request (e.g. client sends another RPC for another user action), then the producer checks if this request has a confirmation for previously sent message (e.g. for the previous UIDL update that server sent to client). If the confirmation is there, then server deletes the corresponding message from the buffer, otherwise it re-sends it again in the current response along with the current UI update. Then the consumer receives two responses instead of one (if, of course, message is not lost again).

This is illustrated by the sequence diagram below: first UIDL message is logged, then deleted after confirmation. Second UIDL message is lost and server re-sends it again after action 3. Then browser receives two UIDL messages (2 and 3), updates the UI and sends the confirmation in the next request.

Server-Client buffer 2

Acceptance Criteria:

  • Vaadin implements "Fault-tolerance messaging" against message loose due to various network errors by using message buffers on both sides. Server (Flow server) maintains a message buffer for UIDL messages that it sends upon request from browser. Browser (Flow client) maintains a similar message buffer for RPC messages that it sends upon end-user actions. UIDL message log is per UI instance.
  • The messages in buffers are discarded once a confirmation is received from the consumer, in the same time the producer keeps the message(s) in the buffer and sends them in a response until it gets a confirmation.
  • Buffers have a guard agains message overflow, e.g. due to unexpected producing of the messages, bugs in Vaadin.
  • Consumer doesn't send a confirmation immediately, but on the next request to producer, to avoid extra traffic.
  • Producer is able to send multiple messages in a single response, e.g. two or more UIDL JSONs, and consumer is able to process them in order.
  • This buffering mechanism is applied to all existing logic, where server decides to trigger a re-sync (full page reload), except cases, when Vaadin cannot avoid this re-sync, e.g. when an intermediate state is lost and producer cannot re-send it, i.e. oldest server side message has bigger ID than current ID on client, that may happen because of misconfiguration of sessions replication. In such a cases Vaadin logs an error message giving a root cause explanation and a way to eliminate it, then makes a re-sync.
  • Stateless applications are not affected by this feature and works as previously.

Additional context

Better to do it in two steps:

  • apply only the server-side buffer, release/test/monitor/fix issues.
  • apply the client-side buffer.

Target Vaadin release - 24.6, but can be picked to older versions.

@mshabarov mshabarov moved this to 🪵Product backlog in Vaadin Flow ongoing work (Vaadin 10+) Oct 28, 2024
@mshabarov mshabarov changed the title Re-send UIDL and RPC messages if they are lost Fault-tolerance messaging for server-client communication Oct 28, 2024
@mshabarov mshabarov changed the title Fault-tolerance messaging for server-client communication Fault-tolerant messaging for server-client communication Oct 28, 2024
@mshabarov
Copy link
Contributor Author

mshabarov commented Oct 30, 2024

UPD:

Vaadin already uses some caching:

  • Atmosphere caches the messages on the server-side, this is how it's configured in PushRequestHandler:
        atmosphere.addInitParameter(ApplicationConfig.BROADCASTER_CACHE,
                UUIDBroadcasterCache.class.getName());

What we need else is server-side buffer that stores server response messages and re-sends them to client, if these messages are not yet confirmed by client.

Currently the server doesn't re-send the response, if the client resends the request once again (some deviations from real logic are possible):

  • client caches the request and sends a request to server (suppose the id=5)
  • server processes the request and sends a response, increments the id, so next time it expects id=6
  • response is lost
  • client has no response and re-sends the same request once again (taken from cache) with id=5
  • server receives this second request, but ignores it, because the sync id is less that it expects (expects 6, but actual is 5), it checks it's hash. If the hash is the same, it just logs a warning, if it's different, it throws an exception (maybe the exact logic is slightly different, but the truth is that the server doesn't re-send the response again).

We have to avoid the ignoring of the request that client re-sends. Server should re-send the response in such cases.

@mshabarov mshabarov moved this from 🪵Product backlog to 🟢Ready to Go in Vaadin Flow ongoing work (Vaadin 10+) Nov 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: 🪵Product backlog
Development

No branches or pull requests

1 participant