Question

I am using Wicket with an embedded Jetty webserver. The application is using websockets, therefore the Jetty setup looks the following:

FilterHolder filterHolder = new FilterHolder(Jetty9WebSocketFilter.class);
filterHolder.setInitParameter("applicationClassName", "MyApplication");
filterHolder.setInitParameter("filterMappingUrlPattern", "/*");

WebAppContext context = new WebAppContext();
context.setResourceBase(".");
context.addFilter(filterHolder, "/*", null);
context.addServlet(DefaultServlet.class, "/*");

Server server = new Server(8083);
server.setHandler(context);

try {
    server.start();
} catch (Exception e) {
    e.printStackTrace();
}

Everything works fine, besides the websocket timeout. Research showed that Jetty's websocket connections time out, although this is not common for webservers.

After researching I stumbled upon the following init parameter, that I now pass to my filterHolder:

filterHolder.setInitParameter("maxIdleTime", "5000");

And apparently this parameter does something - because now the timeout occurs notably faster than before, exactly after 5 seconds.

But I couldn't figure out how I can disable the timeout completely. Using -1, 0 or even Integer.MIN_VALUE instead of 5000 does nothing, there is still a timeout after a while. The documentation I found says nothing about an according value.

What init parameter can I use to disable the websocket timeout? Or do I have to stick with setting the timeout to some ridiculously high value?

Était-ce utile?

La solution

Jetty 9.1 has its own WebSocketUpgradeFilter, use that one, and then modify the default policy's idle timeout.

Example:

package jetty.websocket;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter;
import org.eclipse.jetty.websocket.server.pathmap.ServletPathSpec;
import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
import org.eclipse.jetty.websocket.servlet.WebSocketCreator;

public class JettyWebSocketViaFilter
{
    @WebSocket
    public static class EchoSocket
    {
        @OnWebSocketMessage
        public void onMessage(Session session, String msg)
        {
            session.getRemote().sendStringByFuture(msg);
        }
    }

    public static class EchoCreator implements WebSocketCreator
    {
        private EchoSocket echoer = new EchoSocket();

        @Override
        public Object createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp)
        {
            return echoer;
        }
    }

    public static void main(String[] args)
    {
        Server server = new Server();
        ServerConnector connector = new ServerConnector(server);
        connector.setPort(8080);
        server.addConnector(connector);

        // Setup the basic application "context" for this application at "/"
        // This is also known as the handler tree (in jetty speak)
        ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
        context.setContextPath("/");
        server.setHandler(context);

        // Add the websocket filter
        WebSocketUpgradeFilter wsfilter = WebSocketUpgradeFilter.configureContext(context);
        wsfilter.getFactory().getPolicy().setIdleTimeout(5000);
        wsfilter.addMapping(new ServletPathSpec("/"),new EchoCreator());

        // The filesystem paths we will map
        String staticRoot = "src/main/webapp/websocket/protocol";

        ServletHolder holderDefault = new ServletHolder("default",DefaultServlet.class);
        holderDefault.setInitParameter("resourceBase",staticRoot);
        holderDefault.setInitParameter("dirAllowed","true");
        context.addServlet(holderDefault,"/");

        try
        {
            server.start();
            server.join();
        }
        catch (Throwable t)
        {
            t.printStackTrace(System.err);
        }
    }
}

Timeouts in Jetty with WebSockets:

Since WebSocket is an upgraded HTTP/1.1 request you have essentially 2 timeouts to worry about.

First is the connector idle timeout, that will be used for the HTTP/1.1 initial portion of the incoming Upgrade request. This is configured at the server level, with the connector that it has. With Jetty, any value 0 or below is considered an infinite timeout.

Next, you have the websocket endpoint specific idle timeout. If it has a value greater than 0, then it is applied to already established connection's idle timeout (the one from the server side).

Some combinations and what it means ...

Server Connector IdleTimeout  | WebSocket Endpoint IdleTimeout | Actual Timeout
------------------------------+--------------------------------+----------------
   30,000 ms                  |       -1                       |   30,000 ms
   30,000 ms                  |   10,000 ms                    |   10,000 ms
   30,000 ms                  |  400,000 ms                    |  400,000 ms
  500,000 ms                  |       -1                       |  500,000 ms
  500,000 ms                  |      200 ms                    |      200 ms
       -1                     |       -1                       |  (infinite)
       -1                     |    1,000 ms                    |    1,000 ms

You can think of the Server Connector IdleTimeout as a TCP level timeout, while the WebSocket endpoint timeout is an application level idle timeout.

Hope this helps.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top