Search code examples
javaserverjerseyshutdowngrizzly

What is the proper way to gracefully shutdown a Grizzly server? (Embedded with Jersey)


I have the following piece of code to start a basic Embedded Grizzly server running with Jersey.

  private static void startServer() {
    ServerResourceConfiguration configuration = new ServerResourceConfiguration();

    HttpServer server = GrizzlyHttpServerFactory.createHttpServer(
            URI.create(BASE_URI),
            configuration,
            false,
            null,
            false);

    server.start();

    if (System.in.read() > -2) {
      server.shutdownNow();
    }
  }

This does not look like production level way to stop a server. What is the best practice to gracefully shut it down ? I guess a terminal command of some sort. Killing the process would work but it is not very graceful.

I am using Gradle on this project and runs the server with the gradle run command. Could a Gradle task do the job?

Also I have seen this about gracefully terminating a grizzly transport: http://grizzly-nio.net/2013/08/gracefully-terminating-a-grizzly-transport/ But I am not sure if I would need to use it. I don't understand how to use it.

EDIT: I came across this post: https://stackoverflow.com/a/15391081/3982755 Is that an acceptable way to terminate an Http server in a production environment?


Solution

  • There is no answer so I will post my own, I implemented it with a Shutdown Hook and it works very well.

    • The server will wait for all connections to terminate before shutting down.
    • To avoid getting blocked for ever if a connection never terminates, we set a grace period(60 seconds)
    • After the grace period the server will force termination of all connections

    Here is the code for the hook to be run when the server receives a SIGINT or SIGTERM signal.

    public class GrizzlyServerShutdownHookThread extends Thread {
    
      public static final String THREAD_NAME = "Grizzly Server Shutdown Hook";
    
      public static final int GRACE_PERIOD = 60;
      public static final TimeUnit GRACE_PERIOD_TIME_UNIT = TimeUnit.SECONDS;
    
      private final HttpServer server;
    
      /**
       * @param server The server to shut down
       */
      public GrizzlyServerShutdownHookThread(HttpServer server) {
        this.server = server;
        setName(THREAD_NAME);
      }
    
      @Override
      public void run() {
        LOG.info("Running Grizzly Server Shutdown Hook.");
        LOG.info("Shutting down server.");
        GrizzlyFuture<HttpServer> future = server.shutdown(GRACE_PERIOD, GRACE_PERIOD_TIME_UNIT);
    
        try {
          LOG.info(format("Waiting for server to shut down... Grace period is %s %s", GRACE_PERIOD, GRACE_PERIOD_TIME_UNIT));
          future.get();
        } catch(InterruptedException | ExecutionException e) {
          LOG.error("Error while shutting down server.", e);
        }
    
        LOG.info("Server stopped.");
      }
    }
    

    Then I register the Hook into the RunTime object this way when I setup the server:

    Runtime.getRuntime().addShutdownHook(
        new GrizzlyServerShutdownHookThread(server)
    );
    

    And finally, I start the server this way:

    try {
      server.start();
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
    // wait for a SIGINT (Ctrl+c) signal to shut down
    try {
      LOG.info("Press CTRL^C to exit..");
      Thread.currentThread().join();
    } catch(InterruptedException e) {
      throw new RuntimeException(e);
    }