diff --git a/core/src/main/java/io/grpc/ServerImpl.java b/core/src/main/java/io/grpc/ServerImpl.java index 45ff8011f0..094aab3782 100644 --- a/core/src/main/java/io/grpc/ServerImpl.java +++ b/core/src/main/java/io/grpc/ServerImpl.java @@ -200,6 +200,15 @@ public class ServerImpl implements Server { return terminated; } + /** + * Waits for the server to become terminated. + */ + public synchronized void awaitTerminated() throws InterruptedException { + while(!terminated) { + wait(); + } + } + /** * Returns whether the server is terminated. Terminated servers have no running calls and * relevant resources released (like TCP connections). diff --git a/netty/src/main/java/io/grpc/transport/netty/NettyServerBuilder.java b/netty/src/main/java/io/grpc/transport/netty/NettyServerBuilder.java index 2200e728b9..6e929c1b86 100644 --- a/netty/src/main/java/io/grpc/transport/netty/NettyServerBuilder.java +++ b/netty/src/main/java/io/grpc/transport/netty/NettyServerBuilder.java @@ -40,6 +40,7 @@ import io.grpc.SharedResourceHolder; import io.grpc.transport.ServerListener; import io.netty.channel.EventLoopGroup; import io.netty.handler.ssl.SslContext; +import io.grpc.ServerImpl; import java.net.InetSocketAddress; import java.net.SocketAddress; @@ -88,6 +89,15 @@ public final class NettyServerBuilder extends AbstractServerBuilderThe server won't take ownership of the given EventLoopGroup. It's caller's responsibility * to shut it down when it's desired. + * + *

Grpc uses non-daemon {@link Thread}s by default and thus a {@link ServerImpl} will + * continue to run even after the main thread has terminated. However, users have to be cautious + * when providing their own {@link EventLoopGroup}s. + * For example, Netty's {@link EventLoopGroup}s use daemon threads by default + * and thus an application with only daemon threads running besides the main thread will exit as + * soon as the main thread completes. + * A simple solution to this problem is to call {@link ServerImpl#awaitTerminated()} to + * keep the main thread alive until the server has terminated. */ public NettyServerBuilder userBossEventLoopGroup(EventLoopGroup group) { this.userBossEventLoopGroup = group; @@ -102,6 +112,15 @@ public final class NettyServerBuilder extends AbstractServerBuilderThe server won't take ownership of the given EventLoopGroup. It's caller's responsibility * to shut it down when it's desired. + * + *

Grpc uses non-daemon {@link Thread}s by default and thus a {@link ServerImpl} will + * continue to run even after the main thread has terminated. However, users have to be cautious + * when providing their own {@link EventLoopGroup}s. + * For example, Netty's {@link EventLoopGroup}s use daemon threads by default + * and thus an application with only daemon threads running besides the main thread will exit as + * soon as the main thread completes. + * A simple solution to this problem is to call {@link ServerImpl#awaitTerminated()} to + * keep the main thread alive until the server has terminated. */ public NettyServerBuilder workerEventLoopGroup(EventLoopGroup group) { this.userWorkerEventLoopGroup = group;