简体   繁体   English

保持Dotnet Core Grpc Server作为控制台应用程序运行?

[英]Keep Dotnet Core Grpc Server running as a console application?

I am trying to keep a Grpc server running as a console daemon. 我试图让一台Grpc服务器作为控制台守护程序运行。 This gRPC server is a microservice that runs in a docker container. 这个gRPC服务器是一个在docker容器中运行的微服务。

All of the examples I can find make use of the following: 我能找到的所有例子都使用以下内容:

Console.ReadKey();

This does indeed block the main thread and keeps it running but does not work in docker with the following error: 这确实会阻塞主线程并使其保持运行但在docker中不起作用,并出现以下错误:

"Cannot read keys when either application does not have a console or when console input has been redirected. Try Console.Read."

Now I could probably try to find a workaround for docker specifically, but this still doesn't feel right. 现在我可能会尝试专门为docker找到解决方法,但这仍然感觉不对。 Does anyone know of a good "production ready" way to keep the service running? 有没有人知道一个良好的“生产就绪”方式来保持服务运行?

You can now use Microsoft.Extensions.Hosting pacakge which is a hosting and startup infrastructures for both asp.net core and console application. 您现在可以使用Microsoft.Extensions.Hosting pacakge,它是asp.net核心和控制台应用程序的托管和启动基础结构。

Like asp.net core, you can use the HostBuilder API to start building gRPC host and setting it up. 与asp.net核心一样,您可以使用HostBuilder API开始构建gRPC主机并进行设置。 The following code is to get a console application that keeps running until it is stopped (for example using Control-C): 以下代码是为了让控制器应用程序一直运行直到它被停止(例如使用Control-C):

using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;

public class Program
{
    public static async Task Main(string[] args)
    {
        var hostBuilder = new HostBuilder();

         // register your configuration and services.
        ....

        await hostBuilder.RunConsoleAsync();
    }
}

In order to run the gRPC service, you need to start/stop Grpc.Core.Server in a hosted service. 要运行gRPC服务,您需要在托管服务中启动/停止Grpc.Core.Server A hosted service is basically a piece of code that is run by the host when the host itself is started and the same for when it is stopped. 托管服务基本上是主机本身启动时由主机运行的一段代码,而停止时则由托管服务运行。 This is represented in the IHostedService interface. 这在IHostedService接口中表示。 That's to say, implement a GrpcHostedService to override the interface: 也就是说,实现一个GrpcHostedService来覆盖接口:

using System.Threading;
using System.Threading.Tasks;
using Grpc.Core;
using Microsoft.Extensions.Hosting;

namespace Grpc.Host
{
    public class GrpcHostedService: IHostedService
    {
        private Server _server;

        public GrpcHostedService(Server server)
        {
            _server = server;
        }

        public Task StartAsync(CancellationToken cancellationToken)
        {
            _server.Start();
            return Task.CompletedTask;
        }

        public async Task StopAsync(CancellationToken cancellationToken) => await _server.ShutdownAsync();
    }
}

It's simple really. 这真的很简单。 We get an GrpcHostedService instance injected through dependency injection and run StartAsync on it when host is started. 我们得到一个通过依赖注入注入的GrpcHostedService实例,并在启动主机时对其运行GrpcHostedService When the host is stopped we run StopAsync so that we can gracefully shut everything down including Grpc server. 当主机停止时,我们运行StopAsync,以便我们可以优雅地关闭所有内容,包括Grpc服务器。

Then go back to the Program.cs and make some changes: 然后返回Program.cs并进行一些更改:

public class Program
{
    public static async Task Main(string[] args)
    {
        var hostBuilder = new HostBuilder()
             // Add configuration, logging, ...
            .ConfigureServices((hostContext, services) =>
            {
                // Better to use Dependency Injection for GreeterImpl
                Server server = new Server
                {
                    Services = {Greeter.BindService(new GreeterImpl())},
                    Ports = {new ServerPort("localhost", 5000, ServerCredentials.Insecure)}
                };
                services.AddSingleton<Server>(server);
                services.AddSingleton<IHostedService, GrpcHostedService>();
            });

        await hostBuilder.RunConsoleAsync();
    }
}

By doing this, the generic host will automatically run StartAsync on our hosted service, which in turn will call StartAsync on the Server instance, essentially start the gRPC server. 通过这样做,通用主机将在我们的托管服务上自动运行StartAsync,而后者将在Server实例上调用StartAsync,实质上是启动gRPC服务器。

When we shut down the host with Control-C, the generic host will automatically call StopAsync on our hosted service, which again will call StopAsync on the Server instance which will do some clean up. 当我们使用Control-C关闭主机时,通用主机将自动在我们的托管服务上调用StopAsync,这将再次调用Server实例上的StopAsync,它将进行一些清理。

For other configuration in HostBuilder, you can see this blog . 对于HostBuilder中的其他配置,您可以看到此博客

Use ManualResetEvent to block the main thread until you receive a shutdown event. 使用ManualResetEvent阻止主线程,直到收到关闭事件。

For example in a trivial situation: 例如在一个微不足道的情况:

class Program
{
  public static ManualResetEvent Shutdown = new ManualResetEvent(false);

  static void Main(string[] args)
  {
    Task.Run(() =>
    {
      Console.WriteLine("Waiting in other thread...");
      Thread.Sleep(2000);
      Shutdown.Set();
    });

    Console.WriteLine("Waiting for signal");
    Shutdown.WaitOne();

    Console.WriteLine("Resolved");
  }
}

For example, in your case, I imagine something like: 例如,在您的情况下,我想象的是:

using System;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using Grpc.Core;
using Helloworld;

namespace GreeterServer
{
  class GreeterImpl : Greeter.GreeterBase
  {
    // Server side handler of the SayHello RPC
    public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
    {
      Program.Shutdown.Set(); // <--- Signals the main thread to continue 
      return Task.FromResult(new HelloReply {Message = "Hello " + request.Name});
    }
  }

  class Program
  {
    const int Port = 50051;

    public static ManualResetEvent Shutdown = new ManualResetEvent(false);

    public static void Main(string[] args)
    {
      Server server = new Server
      {
        Services = {Greeter.BindService(new GreeterImpl())},
        Ports = {new ServerPort("localhost", Port, ServerCredentials.Insecure)}
      };
      server.Start();

      Shutdown.WaitOne(); // <--- Waits for ever or signal received

      server.ShutdownAsync().Wait();
    }
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 DotNet核心控制台应用程序:AutoMapper - DotNet Core Console Application: AutoMapper Dotnet 核心控制台应用程序松弛机器人记录器 - Dotnet core Console Application slack bot logger 在 Do.net Framework 4.8 客户端中使用核心 gRPC 服务器? - Use Core gRPC Server in Dotnet Framework 4.8 client? 运行 .NET 核心控制台应用程序 - Running a .NET Core Console Application 在本地IIS服务器上运行DotNet Core Web应用程序的正确安装顺序是什么? - What is the correct order of installation for running a DotNet Core web application on a local IIS server? 从控制台运行dotnet core应用程序时无法解决依赖关系 - Unable to resolve dependency when running dotnet core app from console 使用ServiceCollection的dotnet core 2.0控制台应用程序中的循环依赖关系 - circular dependency in dotnet core 2.0 console application using ServiceCollection DotNet Core 控制台应用程序:应用程序依赖项清单中指定的程序集 - DotNet Core console app: An assembly specified in the application dependencies manifest 如何以编程方式停止/退出/终止 dotnet core HostBuilder 控制台应用程序? - How to stop/exit/terminate dotnet core HostBuilder console application programmatically? 从 grpc.core 迁移到 grpc-dotnet - migrating from grpc.core to grpc-dotnet
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM