Docker中长期运行的C#流程

时间:2018-08-17 12:18:16

标签: c# docker

我有一个用C#编写的Windows服务。应用程序的“大脑”位于名为Driver的类中。此类异步启动一堆线程来执行许多操作。这段代码中没有任何“阻塞”。驱动程序负责启动这些线程,侦听特定事件并在这些事件上停止线程。

这时,我已将此代码包装为Windows服务。 OnStartOnStop等方法只是此类的包装。 Windows服务可以按照我的意愿运行。但是,现在,我想在Docker容器中运行此代码。我的问题是,如何修改此代码以使其成为一个长期运行的过程,而不是Windows服务。

我最初的想法是将代码包装在控制台应用程序中。然后,将代码从OnStart移动到Console应用程序的主体。在该代码之后,我将只有一个while(true){}语句以使控制台应用程序保持活动状态。但是,这感觉像是黑客。

这种方法是黑客吗?或者,是否有“真正的”方法来做到这一点?如果是这样,在Docker中具有长期运行的C#应用​​程序的推荐方法是什么?

3 个答案:

答案 0 :(得分:3)

使用dotnet core 2.1,您还可以在Microsoft.Extensions.Hosting提供的控制台应用程序中使用aspnet已知的IHostedService。结合使用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();
}

答案 1 :(得分:1)

托管进程(例如Windows服务)比在紧密循环(while(true) {})中运行的控制台应用程序更好。由于您打算在Docker容器中运行它,因此建议您查看以.Net Core为目标的AspNet Core,以便可以使用Linux基本映像(映像大小较小)。 AspNet Core提供了一个Web服务器(Kestrel),在这种情况下,它将作为托管过程。

要在AspNet Core中运行长时间运行的任务,请查看Asp.Net core long running task

答案 2 :(得分:1)

由于您希望将应用程序作为Docker容器运行,因此我想您也希望在Linux上运行它。然后,我认为您可以将代码定位到支持在Windows和Linux(以及Mac)上运行的.NET Core。

有一个名为Microsoft.Extensions.Hosting的软件包,它是asp.net核心和dotnet核心控制台应用程序的宿主和启动基础结构,它有助于管理整个生命周期的过程。它的ConsoleLifetime类将处理在名为IHostedService的接口中定义的常规乘法启动/停止方法。

您只需要实现自己的IHostedService(或从BackgroundService类继承)并将其添加到ConfigureServies中的宿主上下文中即可。

这是一个示例托管服务:

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();
    }
}

然后修改您的主要方法:

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();
    }
}