Dropwizard 的自定义 gRPC 命令立即退出

Custom gRPC command for Dropwizard exits immediately

我使用启动 gRPC 服务器的 Dropwizard 创建了一个应用程序。我不使用常规服务器,而是想使用 java -jar my-fat.jar grpc config.yml 来启动我的应用程序。

我已经通过覆盖应用程序中的相应方法将命令添加为启动期间唯一可用的命令 class:

public class App extends Application<Configuration> {

    public static void main(String[] args) throws Exception {
        new App().run(args);
    }

    @Override
    protected void addDefaultCommands(final Bootstrap<Configuration> bootstrap) {
        bootstrap.addCommand(new GrpcCommand(this));
    }
}

我可以使用 java -jar my-fat.jar grpc config.yml 启动我的应用程序。我的命令如下所示:

public class GrpcCommand extends EnvironmentCommand<Configuration> {

    public GrpcCommand(Application<Configuration> application) {
        this(application, "grpc", "Runs the Dropwizard application as a gRPC server");
    }

    /**
     * Creates a new environment command.
     *
     * @param application the application providing this command
     * @param name        the name of the command, used for command line invocation
     * @param description a description of the command's purpose
     */
    protected GrpcCommand(final Application<Configuration> application, final String name, final String description) {
        super(application, name, description);
    }

    @Override
    protected void run(final Environment environment, final Namespace namespace, final Configuration configuration) throws Exception {
        final var certificateService = AzureCertificateService.createWithClients(
                AzureSecretClient.create(configuration.getKeyVaultConfiguration()),
                AzureCertificateClient.create(configuration.getKeyVaultConfiguration())
        );

        final var validationService = CertificateValidationService.create(certificateService);
        final var signingService = CertificateSigningService.create(certificateService);

        final Pair<X509Certificate, KeyPair> certificate = certificateService.getSigningCertificateWithKeyPair();

        final BaseApiImpl baseApi = new BaseApiImpl(validationService, signingService);
        final GrpcServer grpcServer = GrpcServer.newBuilder()
                .withBaseApi(baseApi)
                .withConfiguration(configuration.getGrpcConfiguration())
                .withCertificate(certificate.getLeft())
                .withPrivateKey(certificate.getRight().getPrivate())
                .build();

        new Thread(() -> {
            try {
                grpcServer.start();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).run();

        environment.healthChecks().register("grpc-server", new GrpcServerHealthCheck(grpcServer));
    }
}

线程的启动方式不适合生产使用,我只是想继续前进。 GrpcServerclass的启动方法:

@Override
public void start() throws Exception {
    final NettyServerBuilder nettyServerBuilder = NettyServerBuilder.forPort(configuration.getPort())
            .addService(baseApi)
            .intercept(new OriginInterceptor());

    if (certificate != null && privateKey != null) {
        LOG.info("Got certificate and private key, enabling SSL");
        nettyServerBuilder.sslContext(buildSslContext());
    }

    server = nettyServerBuilder
            .build()
            .start();

    LOG.info("Server started at port {}", server.getPort());
}

而且我在启动时在我的日志中看到消息 GrpcServer: Server started at port 50441。但是,应用程序不会保持打开状态。我错过了什么?我对线程的使用不应该创建一个线程来阻止应用程序退出吗?如何在 gRPC 服务器启动后保留应用程序 运行?

当我禁用服务器命令时,Jetty 也没有启动(当然),这使应用程序之前保持活动状态。

我在 gRPC Hello World Example 中找到了最简单的解决方案。

我的启动方法现在看起来像这样:

public void start() throws Exception {
    // Everything else as above

    Runtime.getRuntime().addShutdownHook(new Thread(GrpcServer.this::stop));
    LOG.info("Server started at port {}", server.getPort());
    blockUntilShutdown();
}

private void blockUntilShutdown() throws InterruptedException {
    if (server != null) {
        server.awaitTermination();
    }
}