Thursday, August 26, 2010

GAE and Tapestry5 Exception Handling

Tapestry5 uses its own technique to process unhandled exceptions.
When unhandled exception occurs Tapestry5 redirects response to special error page which is responsible to display exception detail.

There is a standard error page in Tapestry5 that can be very helpful for developer if you configure your application to run in development mode. To do this you contribute SymbolConstants.PRODUCTION_MODE symbol with value "false" in your like this:

public static void contributeApplicationDefaults(
MappedConfiguration<String, String> configuration)
// ...
configuration.add(SymbolConstants.PRODUCTION_MODE, "false");
// ...

Standard error page provides you all necessary information to understand the cause of exception:

And here is how exception report looks like in production:

This is reasonable, because in production you usually don't want to display all this information to clients. But this is also not so user friendly, because it displays value of Throwable.getMessage().

Tapestry5 allows overriding standard error page with your own exception page so you can display more user friendly messages.

There's also another scenario when you don't want Tapestry5 to generate exception report, and let application server provide static HTML page with apologizes to client. This approach better suits for production, but in development mode its better to leave detailed error report as is.

To change the way Tapestry5 handles exceptions you should provide another implementation of RequestExceptionHandler. One way doing this is to decorate RequestExceptionHandler:

public RequestExceptionHandler decorateRequestExceptionHandler(
final Logger logger,
final Response response,
boolean productionMode)
// Leave default implementation of RequestExceptionHandler in development mode
if (!productionMode) return null;

// Provide simple implementation that logs exception and returns
// HTTP error code which will be handled by application server
return new RequestExceptionHandler()
public void handleRequestException(Throwable exception) throws IOException
logger.error("Unexpected runtime exception", exception);

// Return HTTP error code 500
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, null);

Next, add this markup to web.xml:


Now in case of any exceptions client will see contents of 500.html.

This approach have one more advantage for GAE. Generating exception reports consumes billable CPU cycles and takes request processing time.

Saving CPU cycles is good. And there is one note about request processing time. As you may know on GAE each request have to be processed in 30 seconds. If it doesn't, then runtime raises DeadlineExceededException and gives application few hundreds of milliseconds to fail gracefully. As practice shows, default T5 RequestExceptionHandler + error report generation usually takes longer.

One more note about GAE exception handling. Since version 1.3.6 GAE allows developers declare custom static error handlers for GAE specific errors: over_quota, dos_api_denial and timeout.
In case of first two errors GAE doesn't even pass requests to application code. Timeout errors appear as a result of application code execution and (I suppose) this static error handler may conflict with RequestExceptionHandler that overrides DeadlineExceededException with HTTP error code 500.

I also want to share my implementation of over_quota.html page. I noticed free quotas got reset every day near 11am-12am Moscow Summer Time (its around 7am-8am UTC time, not sure if it the same for another applications). I thought it would be good if I include how many time is it left for GAE enabled free quotas next time. And though over_quota.html is a static page it is possible to include a peace of javascript that calculates this time in client timezone. Here is it:

<title>Ping Service - Over Capacity</title>
Over Capacity

We apologize for the inconvenience.

Service is temporary unavailable until <span id="deadline">8:00 am UTC time.</span>

<script type="text/javascript">
var element = document.getElementById("deadline");
var now = new Date();
var deadline = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 8);
var timezoneOffset = now.getTimezoneOffset() / 60;
deadline.setHours(deadline.getHours() - timezoneOffset);
if (deadline <= now) {
deadline.setDate(deadline.getDate() + 1);
element.innerHTML = deadline.toLocaleTimeString().replace(/:00$/, "")
+ " your time ("
+ Math.round((deadline - now) / 60 / 60 / 1000)
+ " hours left).";

See also


  1. Hi Dmitry,

    Thanks for the great page on Exception.
    We are having strange issue in our dev environment.

    The Production_mode is set to false in but the application does not show the complete exception page. Have you dealt with such a case before?

  2. Hi,

    In production mode there's _should_ be detailed exception report. Make sure 1) you're not overriding Exception page with your own 2) no other code set PRODUCTION_MODE symbol to true prior to your code in AppModule 3) no system property -Dtapestry.production-mode=true set
    (once set you can't override system properties in runtime)

    You may also find the following discussion of this blog post useful:

    Hope this helped

  3. Thanks for the response.

    I checked as much as I could but there isn't anything that sets Production_Mode to true in that project.
    Finally I resorted to supplying -Dtapestry.production-mode=false in Tomcat's VM Arguments. It worked but I am still looking for the root cause.
    Thanks Again

  4. Totally my fault :)

    The "services" package was named "service".
    So Tapestry could not find the and was loading the default which sets Production_Mode to true.