I’m deploying a GWT app on Amazon’s EC2 architecture behind an ELB and wanted to ensure the best experience for users while pushing out new code updates.
This is a short review of my most-likely-accurate findings. It is not well organized and basically a public mind dump vs. a private mind dump to my other team members.
I’m not going to review GWT RPC in detail, but the basic points for us are:
- GWT on the server-side will serialize/deserialize:
- Anything that implements GWT’s
- Anything that implements Java’s
Serializableand is in a serialization policy file (see this faq entry for more details)
- Anything that implements GWT’s
- GWT on the client-side will serialize/deserialize any type it knew about at compile-time
Here’s what a typical RPC request might look like:
POST https://app.com/gwtapp/dispatch Content-Type: text/x-gwt-rpc; charset=UTF-8 Origin: https://app.com Referer: https://app.com/gwtapp/361924868514EB67231B0C48DC4B136A.cache.html X-GWT-Module-Base: https://app.com/gwtapp/ X-GWT-Permutation: 361924868514EB67231B0C48DC4B136A <serialized-objects-here>
The interesting thing to notice is the
X-GWT-Permutation header–this is the strong name (hash) of the browser/locale/etc. code base the client is currently running.
When an old client sends an RPC request to a new server, we would ideally like to fulfill it as long as we haven’t changed the contract of the RPC service it’s interacting with.
GWT’s deserialization execution flow for an old request is something like:
- Read in the
- Try to load the serialization policy file based on the permutation header–however, this will fail because this is a new server that does not have the old serialization policy file
- Fall back on
IsSerializablecan be deserialized
For this reason, it’s important to still use the old
IsSerializable marker interface even though GWT now supports Java’s
Also, type name elision cannot be used because it also relies on the serialization policy file.
Then, assuming the RPC contract is the same, everything should still work.
If the RPC contract does change, i.e. the old client tries to use changed/removed functionality, they will get an IncompatibleRemoteServiceException which the GWT client-side code should handle and prompt the user to reload the application.
One additional wrinkle is code split points. If an old client tries to load part of the application it does not have yet, it will use the old code base name, which is no longer on the new server. The client-side
GWT.runAsync will fail with a 404 and the application should prompt the user to reload. (See AsyncSplit for how gerrit handles this.)
The same scenario above can happen here, when the client has a newer serialization policy strong name than the old server, so the old server falls back to the
However, an added wrinkle is the application bootstrapping process.
A client might:
/app.htmland get served by either a new or old server (fine so far)
/app/module.nocache.jsand get served by a new server–this is the GWT bootstrapping code and, based on the user’s browser/locale/etc. combination, it tells the browser to load
/app/new-permuation-name.cache.html, however, this request gets served by an old server that only has the old application files
- Client gets a
404and the application bootstrapping stops
I currently know of no way to recover from this scenario. Because the error happens in between the GWT bootstrapping code and your application code, there is not a way for your application code to detect what has happened and recover.
Update: Thanks for Sripathi Krishnan for pointing out the
gwt:onLoadErrorFn function where you can prompt the user to reload their browser to recover from this scenario.
For this reason, it’s very important to have a clean switch from old to new versions–no old servers should be serving requests once new servers have come online.
Based on my current understanding, to service both old and new clients during a GWT upgrade as elegantly as possible, you should:
IsSerializableand no type name elision in the RPC DTOs
IncompatibleRemoteServiceExceptionin the RPC
- Handle 404’s in the
- Minimize/eliminate the window when both old and new servers are available
Any corrections, feedback, etc., is appreciated.