Folks,
I had some thoughts about how to solve this w/o re-engineering the
GUI... I just had a conversation with Mazz about this to verify some
details about the existing GWT code.
Possible Solution:
There are two types of requests that occur, user-initiated and
non-user-initiated. For user-initiated requests, introduce the notion of
a global request id; since the GUI is single threaded anyways, this
should not matter. User-initiated requests MAY be chained (see example
below) where a single user action causes multiple nested, logically
associated requests, to be dispatched against the server. The key or
mouse event that initially triggers a request chain is the initiating
event. Have the initiating event create a new unique request-id (UUID),
have it immediately and atomically set the [newly introduced] global
request-id state. When RPC requests are sent to the server, tag each
request with the request-id. Responses from the server are tagged with
the same request id as was sent by the client (all perfectly ordinary
HTTP). When async responses are received from the server, have the async
handlers perform a atomic_compare operation; if the operation evaluates
to true, permit the response to be rendered, otherwise drop the response
on the floor.
Example:
user request A: -->
inner request A1 -->
async response <-- A1
inner request A2 -->
user request B: -->
inner request A3 ---> (DROPPED OUTBOUND)
inner request B1 -->
async response <-- A2 (DROPPED INBOUND)
inner request B2 -->
inner request B3 -->
Consequences:
If two user-initiated requests are triggered at very nearly the same
time (see example below), there is an opportunity to optimize the
request pipeline by filtering out requests to be sent if the current
request-id does not match (don't send out A3).
User-initiated requests land you on a new page (in the example, A and B
are user-initiated actions). If this is the case, then there is a
possibility that the user gets a partially rendered view A before it
re-renders as view B, but view B will not contain any inconsistent data,
it will be a consistent view.
Key Classes:
org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup.SessionRpcRequestBuilder.doCreate(String)
org.rhq.enterprise.gui.coregui.client.gwt.CoreGUI
On 08/15/2011 10:28 AM, Ian Springer wrote:
Here's an example of how fast user clicking can cause GUI code to
be
executed in the wrong order thereby causing exceptions and/or unexpected
behavior. The steps listed are executed in order:
1) user clicks on Resource X in tree - browser intercepts click and
calls onClick event handler for tree node
2) getResourceComposite(X) async server call is made - control returns
to browser while waiting for async call to return
3) user clicks on Resource Y in tree - browser intercepts click and
calls onClick event handler for tree node
4) getResourceComposite(Y) async server call is made - control returns
to browser while waiting for async call to return
5) getResourceComposite(X) async server call returns and browser calls
onSuccess() handler which continues rendering X detail view
At this point we're in an inconsistent state because we've begun
rendering both the detail view for X and the detail view for Y at the
same time and both are updating the same ResourceDetailView (resource
header, tabs, etc.).
Essentially any async server calls provide windows of opportunity for
the browser to handle user clicks before GUI code is fully done drawing
the view corresponding to a prior user click.
_______________________________________________
rhq-devel mailing list
rhq-devel(a)lists.fedorahosted.org
https://fedorahosted.org/mailman/listinfo/rhq-devel