How is DeadlineExceededException implemented in Go

2019-03-27 06:10发布

问题:

Applications on Google App Engine must have web requests that return response data within 30 seconds. When this time is exceeded, a DeadlineExceededException exception is thrown:

/time.jsp
java.lang.ClassCastException: com.google.apphosting.api.DeadlineExceededException cannot be cast to javax.servlet.ServletException
    at org.apache.jasper.runtime.PageContextImpl.handlePageException(PageContextImpl.java:754)
    at org.apache.jsp.time_jsp._jspService(time_jsp.java:66)
    at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:94)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:806)
    at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1093)
    at com.google.apphosting.runtime.jetty.SaveSessionFilter.doFilter(SaveSessionFilter.java:35)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
    at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
    at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:360)
    at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
    at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
    at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:712)
    at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
    at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.handle(AppVersionHandlerMap.java:237)
    at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:139)
    at org.mortbay.jetty.Server.handle(Server.java:313)
    at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:506)
    at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:830)
    at com.google.apphosting.runtime.jetty.RpcRequestParser.parseAvailable(RpcRequestParser.java:76)
    at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:381)
    at com.google.apphosting.runtime.jetty.JettyServletEngineAdapter.serviceRequest(JettyServletEngineAdapter.java:125)
    at com.google.apphosting.runtime.JavaRuntime.handleRequest(JavaRuntime.java:235)
    at com.google.apphosting.base.RuntimePb$EvaluationRuntime$6.handleBlockingRequest(RuntimePb.java:4755)
    at com.google.apphosting.base.RuntimePb$EvaluationRuntime$6.handleBlockingRequest(RuntimePb.java:4753)
    at com.google.net.rpc.impl.BlockingApplicationHandler.handleRequest(BlockingApplicationHandler.java:24)
    at com.google.net.rpc.impl.RpcUtil.runRpcInApplication(RpcUtil.java:359)
    at com.google.net.rpc.impl.Server$2.run(Server.java:800)
    at com.google.tracing.LocalTraceSpanRunnable.run(LocalTraceSpanRunnable.java:56)
    at com.google.tracing.LocalTraceSpanBuilder.internalContinueSpan(LocalTraceSpanBuilder.java:510)
    at com.google.net.rpc.impl.Server.startRpc(Server.java:756)
    at com.google.net.rpc.impl.Server.processRequest(Server.java:348)
    at com.google.net.rpc.impl.ServerConnection.messageReceived(ServerConnection.java:459)
    at com.google.net.rpc.impl.RpcConnection.parseMessages(RpcConnection.java:319)
    at com.google.net.rpc.impl.RpcConnection.dataReceived(RpcConnection.java:290)
    at com.google.net.async.Connection.handleReadEvent(Connection.java:419)
    at com.google.net.async.EventDispatcher.processNetworkEvents(EventDispatcher.java:762)
    at com.google.net.async.EventDispatcher.internalLoop(EventDispatcher.java:207)
    at com.google.net.async.EventDispatcher.loop(EventDispatcher.java:101)
    at com.google.net.rpc.RpcService.runUntilServerShutdown(RpcService.java:251)
    at com.google.apphosting.runtime.JavaRuntime$RpcRunnable.run(JavaRuntime.java:373)
    at java.lang.Thread.run(Unknown Source)

How is it done? Do you have any open source code?

回答1:

The Request Timer

A request handler has a limited amount of time to generate and return a response to a request, typically around 30 seconds. Once the deadline has been reached, the request handler is interrupted.

The Java runtime environment interrupts the servlet by throwing a com.google.apphosting.api.DeadlineExceededException. If the request handler does not catch this exception, as with all uncaught exceptions, the runtime environment will return an HTTP 500 server error to the client.

The request handler can catch this error to customize the response. The runtime environment gives the request handler a little bit more time (less than a second) after raising the exception to prepare a custom response.

While a request can take as long as 30 seconds to respond, App Engine is optimized for applications with short-lived requests, typically those that take a few hundred milliseconds. An efficient app responds quickly for the majority of requests. An app that doesn't will not scale well with App Engine's infrastructure.

Part of the runtime == Not using threads. This feature is a modification of the VM for sure, and I wouldn't hold my breath waiting for the source code.



回答2:

I suppose that the mechanism behind this exception is implemented in app engine infrastructure, that is not open source.

However you can use this feature for networking or more generally any I/O bounded code using java.nio (e.g Selector). Instead for CPU bounded code you can use java.util.concurrent (e.g. Future).



回答3:

This can be done as follows, use non-blocking IO, and create a watchdog thread which records the startup time and throws the Exception when the elapsed time has passed. The non-blocking IO tutorial shows how this can be done with the Ping.java example.



回答4:

May be a very late reply, but useful for new learners.

@Override
protected final void doGet(final HttpServletRequest req, final HttpServletResponse res) throws IOException {

    res.setContentType("text/html");
    final PrintWriter out = res.getWriter();
    final String a = req.getParameter("a");
    try {

        for (int i = 0; 1 < 5; i++) {
            out.print("Mode " + a + " Running " + i + " " + MainServlon.doubleIt(i));
            Thread.sleep(90000);
        }

    } catch (final InterruptedException e) {
        e.printStackTrace();
    } catch (final DeadlineExceededException e) {
        out.print("Train is going to stop. Let me close this story for now!");
    }

}