[英]Long Running C# Process in Docker
I have a Windows Service that I wrote in C#. 我有一个用C#编写的Windows服务。 This "brains" of the app are in a class named
Driver
. 该应用程序的“大脑”位于名为
Driver
的类中。 This class asynchronously starts up a bunch of threads to do a number of things. 此类异步启动一堆线程来执行许多操作。 There's nothing "blocking" in this code.
这段代码中没有任何“阻塞”。 The Driver is responsible for starting these threads, listening for specific events, and stopping the threads on these events.
驱动程序负责启动这些线程,侦听特定事件并在这些事件上停止线程。
At this time, I've wrapped this code as a Windows Service. 目前,我已将此代码包装为Windows服务。 The
OnStart
, OnStop
, etc methods are just wrappers into this class. OnStart
, OnStop
等方法只是此类的包装。 The Windows Service runs as I want it to. Windows服务可以按照我的意愿运行。 However, now, I want to run this code in a Docker container.
但是,现在,我想在Docker容器中运行此代码。 My question is, how do I modify this code to become a long running process instead of a Windows Service.
我的问题是,如何修改此代码以使其成为长期运行的过程,而不是Windows Service。
My initial thought was to wrap my code in a Console app. 我最初的想法是将代码包装在控制台应用程序中。 Then, I would move the code from
OnStart
to the body of the Console app. 然后,我将代码从
OnStart
移到Console应用程序的主体。 After that code, I would just have a while(true){}
statement to keep the console app alive. 在该代码之后,我只需要
while(true){}
语句即可使控制台应用程序保持活动状态。 However, this feels like a hack. 但是,这感觉像是黑客。
Is this approach a hack? 这是黑客吗? Or, is there a "real" way to do this?
或者,是否有“真正的”方法来做到这一点? If so, what is the recommended approach for having a long running C# app in Docker?
如果是这样,在Docker中具有长期运行的C#应用程序的推荐方法是什么?
Using dotnet core 2.1 you can use the IHostedService known from aspnet in a console application as well, provided by Microsoft.Extensions.Hosting. 使用dotnet core 2.1,您还可以在Microsoft.Extensions.Hosting提供的控制台应用程序中使用aspnet已知的IHostedService。 Combine that with C# >= 7.1 (check your project settings), where you can use an async Main method, your code would look something like this:
结合使用C#> = 7.1(检查项目设置),在这里可以使用异步Main方法,您的代码将如下所示:
static async Task Main(string[] args)
{
var builder = new HostBuilder(); // from Microsoft.Extensions.Hosting
builder.ConfigureServices(s => s.AddSingleton<IHostedService, YourImplementation>());
await builder.RunConsoleAsync();
}
A hosting process (eg a Windows Service) is better than a console application that runs in a tight loop ( while(true) {}
). 托管进程(例如Windows Service)比在紧密循环(
while(true) {}
)中运行的控制台应用程序更好。 Since you intend to run it in a Docker container, I'd suggest looking at AspNet Core, targeting .Net Core so that you can use a Linux base image (which has a smaller image size). 由于您打算在Docker容器中运行它,因此建议您查看以.Net Core为目标的AspNet Core,以便可以使用Linux基本映像(映像大小较小)。 AspNet Core provides a web server (Kestrel) which will be the hosting process in this case.
AspNet Core提供了一个Web服务器(Kestrel),在这种情况下,它将作为托管过程。
To run a long running task in AspNet Core, have a look at Asp.Net core long running task . 要在AspNet Core中运行长时间运行的任务,请查看Asp.Net core长期运行任务 。
Since you want to run your app as Docker container, I guess you also want to run it on Linux. 由于您希望将应用程序作为Docker容器运行,因此我想您也希望在Linux上运行它。 Then I think you can target your code to .NET Core which supports to run on both Windows and Linux (also Mac).
然后,我认为您可以将代码定位到支持在Windows和Linux(以及Mac)上运行的.NET Core。
There's a package named Microsoft.Extensions.Hosting
which is a hosting and startup infrastructures for both asp.net core and dotnet core console application, it helps to manage your process to life cycle. 有一个名为
Microsoft.Extensions.Hosting
的程序包,它是asp.net核心和dotnet核心控制台应用程序的托管和启动基础结构,它有助于管理整个生命周期的过程。 Its ConsoleLifetime
class would process the general aplication start/stop method which defined in the interface named IHostedService
. 它的
ConsoleLifetime
类将处理通用复制开始/停止方法,该方法在名为IHostedService
的接口中定义。
You just need to implement your own IHostedService
(or inherit from the BackgroundService
class) and add it to host context within ConfigureServies
. 您只需要实现自己的
IHostedService
(或从BackgroundService
类继承)并将其添加到ConfigureServies
主机上下文中即可。
Here's a sample hosted service: 这是一个示例托管服务:
public class TimedHostedService : IHostedService, IDisposable
{
private readonly ILogger _logger;
private Timer _timer;
public TimedHostedService(ILogger<TimedHostedService> logger)
{
_logger = logger;
}
public Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Timed Background Service is starting.");
_timer = new Timer(DoWork, null, TimeSpan.Zero,
TimeSpan.FromSeconds(5));
return Task.CompletedTask;
}
private void DoWork(object state)
{
_logger.LogInformation("Timed Background Service is working.");
}
public Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Timed Background Service is stopping.");
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
public void Dispose()
{
_timer?.Dispose();
}
}
Then modify your main method: 然后修改您的主要方法:
public class Program
{
public static async Task Main(string[] args)
{
var hostBuilder = new HostBuilder()
// Add configuration, logging, ...
.ConfigureServices((hostContext, services) =>
{
// Add your services with depedency injection.
services.AddSingleton<IHostedService, TimedHostedService>();
});
await hostBuilder.RunConsoleAsync();
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.