Reputation: 1649
I'm using Meteor to create dynamic client-side interfaces to a server which is tightly coupled to an external hardware system (i.e., a robot). The server can be in one of three different states (A/B/C), but takes a while to transition between the three states. Depending on which state it is in, I want the client UIs to display a different screen.
I have approached this problem by storing the server state in a Meteor collection and publishing this state variable to all connected clients. A client can call a Meteor method to ask the server to change state (e.g., A->B). As a result, once the server has changed state, the new screen is displayed on the client. I'm using this state variable in client-side templates like this:
<template name="root">
{{#if equals server.state "A"}}
{{> UI_for_state_A}}
{{/if}}
{{#if equals server.state "B"}}
{{> UI_for_state_B}}
{{/if}}
etc.
</template>
However, the state transition on the server may take upwards of 10 seconds to complete. During this time, the client is still displaying the old screen. The client UI feels extremely unresponsive. I have also tried having the server update the state variable in the collection at the beginning of the state transition, but this causes the client to switch to the new screen before the server is ready, meaning none of the data is yet populated or available for the new screen.
What I would like to have is for the client to display a "loading" page while the server is in transition, so that a user knows something is going on, but isn't allowed to click any buttons during the transition.
What's the best practice in Meteor for doing this kind of UI synchronization?
Update: there can be multiple connected clients, which all must be synchronized with the server's state. In addition the server can change its state due to external factors, not necessarily on a client event. All these state updates need to be propagated to all clients.
Upvotes: 0
Views: 437
Reputation: 7680
It sounds like you just need to introduce a third, loading state. Set the value of the state in the server collection to this loading state before starting the state transition, and then set it to the final, changed state upon completion.
Note that your app might still feel a little sluggish on noticing the loading state - so you should define method stubs on the client that simply set the state:
if (Meteor.isClient) {
Meteor.methods({
yourMethodName: function() {
States.insert({state: "loading", timestamp: Date.now()}); // or however you would set the state on the server
}
});
}
This will allow your methods to use latency compensation, so the client will immediately enter the loading state rather than waiting for the server to send a publication update.
Upvotes: 2
Reputation: 5472
This is a typical example of a two-phase-commit strategy. It is often used in database transactions, but can be applied to any state machine.
Basically, you actually have the intermediate states and need to store and reference to those as well.
Please have a look at the mongodb two phase commit tutorial for an example.
There is also a third party meteor package on atmosphere that wraps a good state-machine library.
Upvotes: 2