io.deephaven.server.runner.GrpcServer Maven / Gradle / Ivy
The newest version!
//
// Copyright (c) 2016-2024 Deephaven Data Labs and Patent Pending
//
package io.deephaven.server.runner;
import io.grpc.Server;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
/**
* This interface handles the lifecycle of Netty and Jetty servers in a unified way, while still supporting the use
* cases that Deephaven expects:
*
* - Deephaven wants to initiate stop early in the shutdown process, and block on it after all services have begun to
* stop.
* - gRPC+Netty supports a non-blocking stop, a "stop now", and a pair of await methods, one of which takes a
* timeout.
* - gRPC+Jetty supports a blocking stop with a timeout, and a join() method.
*
* In order to not block on the initial stop call, the Jetty implementation will run stop() in another thread. Since
* Jetty doesn't have an extra "shutdownNow" method, the Netty implementation will use the timeout in another thread to
* decide if it needs to invoke shutdownNow when normal shutdown is taking too long.
*
*/
public interface GrpcServer {
/**
* Starts the server, if possible. Otherwise, throws an exception. If successful, returns.
*
* @throws IOException if there is an error on startup
*/
void start() throws IOException;
/**
* Blocks as long as the server is running, unless this thread is interrupted. If stopWithTimeout has been called
* and the timeout has expired, this will return, and the server will be stopped.
*/
void join() throws InterruptedException;
/**
* Server must stop accepting new streams, but let existing streams continue for now.
*
*
* In theory the listening socket should be freed and available for another application to take it, but this is not
* rigorously tested.
*
*
* To complete shutdown, call stopWithTimeout() after any remaining calls have been completed to the server's
* satisfaction, which will terminate the remaining calls.
*/
void beginShutdown();
/**
* Stops the server, using the specified timeout as a deadline. Returns immediately. Call {@link #join()} to block
* until this is completed.
*
*
* If pending calls do not matter, it is unnecessary to call beginShutdown() before this method.
*
* @param timeout time to allow for a graceful shutdown before giving up and halting
* @param unit unit to apply to the timeout
*/
void stopWithTimeout(long timeout, TimeUnit unit);
/**
* After the server is started, this will return the port it is using.
*
* @return the tcp port that the server is listening on after it has started
*/
int getPort();
static GrpcServer of(Server server) {
return new GrpcServer() {
@Override
public void start() throws IOException {
server.start();
}
@Override
public void join() throws InterruptedException {
server.awaitTermination();
}
@Override
public void beginShutdown() {
server.shutdown();
}
@Override
public void stopWithTimeout(long timeout, TimeUnit unit) {
// gRPC's Server.shutdown is idempotent, so we call it again in case beginShutdown was never invoked
server.shutdown();
// Create and start a thread to make sure we obey the deadline
Thread shutdownThread = new Thread(() -> {
try {
if (!server.awaitTermination(timeout, unit)) {
server.shutdownNow();
}
} catch (InterruptedException ignored) {
}
});
shutdownThread.start();
}
@Override
public int getPort() {
return server.getPort();
}
};
}
}