Mit*_*art 12 c# docker .net-core grpc
我试图让一台Grpc服务器作为控制台守护程序运行.这个gRPC服务器是一个在docker容器中运行的微服务.
我能找到的所有例子都使用以下内容:
Console.ReadKey();
Run Code Online (Sandbox Code Playgroud)
这确实会阻塞主线程并使其保持运行但在docker中不起作用,并出现以下错误:
"Cannot read keys when either application does not have a console or when console input has been redirected. Try Console.Read."
Run Code Online (Sandbox Code Playgroud)
现在我可能会尝试专门为docker找到解决方法,但这仍然感觉不对.有没有人知道一个良好的"生产就绪"方式来保持服务运行?
Fei*_*hou 15
您现在可以使用Microsoft.Extensions.Hostingpacakge,它是asp.net核心和控制台应用程序的托管和启动基础结构.
与asp.net核心一样,您可以使用HostBuilder API开始构建gRPC主机并进行设置.以下代码是为了让控制器应用程序一直运行直到它被停止(例如使用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();
}
}
Run Code Online (Sandbox Code Playgroud)
要运行gRPC服务,您需要Grpc.Core.Server在托管服务中启动/停止.托管服务基本上是主机本身启动时由主机运行的一段代码,而停止时则由托管服务运行.这在IHostedService接口中表示.也就是说,实现一个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();
}
}
Run Code Online (Sandbox Code Playgroud)
这真的很简单.我们GrpcHostedService通过依赖注入获取实例,并在启动主机时对其运行StartAsync.当主机停止时,我们运行StopAsync,以便我们可以优雅地关闭所有内容,包括Grpc服务器.
然后回到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();
}
}
Run Code Online (Sandbox Code Playgroud)
通过这样做,通用主机将自动在我们的托管服务上运行StartAsync,而托管服务又会在Server实例上调用StartAsync,实质上是启动gRPC服务器.
当我们使用Control-C关闭主机时,通用主机将自动在我们的托管服务上调用StopAsync,这将再次调用实例上的StopAsync,Server这将进行一些清理.
对于HostBuilder中的其他配置,您可以看到此博客.
使用ManualResetEvent,直到收到关闭事件,以阻止主线程.
例如在一个微不足道的情况:
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");
}
}
Run Code Online (Sandbox Code Playgroud)
例如,在您的情况下,我想象的是:
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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2841 次 |
| 最近记录: |