Fish Eat Fish: 5 Lessons Learnt in Building an App Engine Game Server

In the previous article, I discussed the 5 key lessons learnt while developing an HTML5 online game client for a ‘Fish Eat Fish’ game prototype. This time around, I’m focusing on the 5 key lessons learnt in developing a Google App Engine (GAE) game server for said game prototype. Please note that these lessons apply specifically to the Java API as that is the API of choice in the studio.

Treat the user record’s user ID as confidential information

The user ID associated with a user’s record retrieved through the user service  is the same for all App Engine applications. In addition, it is immutable for the lifetime of the user account. As such, it should be treated as sensitive information and should not be publicly transmitted, if possible. This is  explicitly stated in the Google User service documentation but it never hurts to a reiterate a key lesson with significant impact on user account and application security.

Use Objectify for datastore operations

We experimented with GAE JDO/JPA, Twig, GAE’s low level datastore API, and Objectify. Objectify wins hands down. Why? Objectify’s primary objective sums it up best.

Objectify-Appengine provides the thinnest convenient layer which addresses (the low level datastore API usability) issues

The only catch is that Objectify is designed only for the App Engine Datastore, so migrating  to a different database system is non-trivial. In addition, Objectify’s latest stable release V3.1 still has some usability issues surrounding transaction commitments and retries but the latest source code repository snapshot implements what looks to be an elegant resolution to the issue.

Enable concurrent server requests to minimize cost

Each web server process/instance processes one request at a time. GAE  spins up additional server instances depending on the incoming request queue size and, most importantly, the server response times. In addition, each instance spun up is guaranteed to consume 0.25 instance hours as billing ends 15 minutes after an instance shuts down (as detailed in GAE’s documentation). One way to reduce costs is to allow each server to handle multiple concurrent requests. This reduces the wait time which, in turn, reduces the probability of new server instances being spun up.

To enable concurrent requests, add the following line into WEB-INF/appengine-web.xml:

<threadsafe>true</threadsafe>

The primary disadvantage of this approach is the additional code complexity of writing multi-threaded safe code.

GAE channels are a great service… once you get past the channel creation/expiry issues

GAE’s lack of support for WebSockets is well documented. Fortunately, it offers up an alternative in the form of its channel service. The channel service is a push network built on top of Google’s GTalk communication backbone. Furthermore, its channel service works on Android’s built-in web browser, which does not support WebSockets at this time. Developers are responsible for handling channel creation, and for handling channel re-instantiation on expiry. However, this is a lot trickier than it seems as GAE applications are charged based on the number of channels created. In addition, channels expire exactly 2 hours after creation and there is no built-in functionality on the server to confirm if a channel creation request is a legitimately channel refresh request or if it’s a malicious DoS attack. Consider yourself warned.

Fortunately, the benefits of using channels far outweigh the annoyance of having to work around those issues. Furthermore, the workaround is fairly straightforward and simple to implement.

Server session inactivity has to be manually implemented

If you’re developing a secure web application, chances are high that you have server sessions enabled (please refer to Google’s official documentation on how to enable server sessions). There are a whole host of issues surrounding App Engine’s server session support ranging from performance issues when updating a session variable to expired sessions lingering in the App Engine datastore. However, my one major pet peeve with GAE’s server session support is that the session inactivity timeout functionality does not work.   We are able to set the inactivity interval through the HttpSession::setMaxInactiveInterval() function but the values don’t have any effect. Upon further investigation, we surmised that the root of the issue is GAE’s server session implementation not rigorously testing for bad client session cookie values.

When GAE creates a server session for the user, it also creates a client session cookie JSESSIONID containing a reference to the server session. As long as the JSESSIONID cookie persists, the server session continues to live irrespective of inactivity interval. Fortunately, there’s a way to overcome this, and that is by manipulating the JSESSIONID cookie:

  • Set the JSESSIONID cookie’s maximum age to the desired inactivity interval
  • Reset the JSESSIONID cookie’s maximum age every time the server receives a user request

Conclusion

There are a lot of advantages to using GAE over other cloud server solutions. Most notably, it drastically simplifies the scalability issue. It also provides a strong and stable alternative to WebSockets via its Channel service. Another major strength is its highly scalable datastore service. Unfortunately, coding for the datastore also happens to be one of the biggest frustrations.

This concludes our series of articles on key lessons learnt during our HTML5 investigation period. Follow this link for the previous article in the series.

Click on this link to see the ‘Fish Eat Fish’ HTML5 game prototype. The game rules hyperlink can be found under the game’s header.

, ,

About ChrisK

Chris Khoo cut his teeth on programming writing BASIC programs on a ZX Spectrum back in 1985. Since then, he's graduated to programming on the web and on nearly all the game consoles released since the mid-90's. Chris remains an active member of the software industry and is currently operating as indie developer and founder of Wappworks Studio.
Comments are closed.