在 docker 中运行 ac# worker 服务有意义吗?

Tob*_*ayn 7 c# docker microservices .net-core asp.net-core

我正在 docker 中开发一个多容器应用程序。其中一项服务是一个长时间运行的 C# 控制台应用程序,它基本上对数据库进行一些轮询并将数据发送到 e 服务器。我只是通过添加以下语句来保持服务运行:

while(true);
Run Code Online (Sandbox Code Playgroud)

现在我正在考虑将此服务更改为 .NET Core 工作服务(甚至是 windows 服务,因为我只在 windows 主机上使用 windows 容器)。我已经阅读了一些关于 worker 服务优点的文章,但是当涉及到容器化应用程序时,它们似乎都已经过时了,因为我的容器无论如何都是作为一种“后台服务”运行的(而且我每个容器/图像只使用一个服务)。所以我的问题是:

与在 docker 中运行控制台应用程序相比,在 docker 中运行核心工作服务有什么好处或缺点吗?

更新:对于“工作人员服务”,我指的是 .NET Core 3.x 中可用的新工作人员服务模板:https : //www.stevejgordon.co.uk/what-are-dotnet-worker-services

gra*_*der 12

简而言之,您的快乐路径代码的功能可能“大致相同”。

然而:

使用“通用主机”的好处是您可以获得 Microsoft 为您创建的可重用组件的好处......而不是滚动您自己的组件。

这意味着(恕我直言)更好的代码,因为您不是亲自处理长期运行过程中的许多常见问题。

基本上,与滚动自己的实现相比,您可以“免费”获得大量管道代码。

在 3.0/3.1 之前,很多此功能已结合到 asp.net 名称空间中。3.0/3.1 更新有很多“把它放到一个让 asp.net 和 .net(非 asp.net)通用的地方”以供使用。又名,将它从 asp.net 中删除。

设置:(专用方法“AddHostedService”)

services.AddHostedService<MyWorkerThatImplementsIHostedService>();
Run Code Online (Sandbox Code Playgroud)

因此,当未来的开发人员查看上述代码时,他们确切地知道发生了什么。(与找出自定义滚动实现相比)

或者在更大的代码示例中:

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureServices(services =>
            {
                services.AddHostedService<MyWorkerThatImplementsIHostedService>();
            });
}
Run Code Online (Sandbox Code Playgroud)

上面的代码~~看起来~~asp.net'ish,但实际上是.net(非asp.net)代码。也就是,你的一致性得到了提高。

关掉:

您将获得所有内置的“关闭”选项。这些是“优雅的”关闭选项……不幸的是,“快乐路径”开发人员通常不会考虑这些选项。如果有任何理由跳进这个迷你图书馆......有某种优雅的退出就是它。硬退出可能会使您的处理处于未知的难以排除故障的状态。

CNLT-C

Programmatically (see https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.hosting.ihostapplicationlifetime.stopapplication?view=dotnet-plat-ext-3.1 )

Kubernetes Shutdown
Run Code Online (Sandbox Code Playgroud)

微软甚至想过“我能不能推迟一些最终关闭”

请参阅:配置 .NET Core 通用主机时如何应用 HostOptions.ShutdownTimeout?

这是一个不错的链接,显示了一些选项(Timer vs Queue vs Monitor)

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-3.1&tabs=visual-studio

您还可以将代码部署为:

容器

视窗服务

** Linux 守护进程(参见https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.hosting.systemd.systemdhelpers.issystemdservice?view=dotnet-plat-ext-3.1)(这通常是传统 dotnet 框架开发人员的新概念)

Azure 应用服务

:::::::::::::::::::: 以前的评论:::::::::::::::::::::::::::: :::::(以下)

……………………

C# 中长时间运行的控制台应用程序

精简版:

使用现代代码部署策略,这不仅仅是技术决策,而是财务决策。

更长的版本:

我最近进行了这个讨论,因为一些代码库已被指定用于“转换为 dotnet 核心”和“我们如何转换旧的 Windows 服务?”。

以下是我的想法:

哲学上。

您必须考虑“我在哪里部署以及需要多少费用?”,而不仅仅是技术问题。你提到了码头工人。但是你如何部署它?库伯斯?(天蓝色的 AKS,其他?)这是一条重要的信息。

恕我直言:使用“云”甚至内部部署的 Kubernetes ......你不想要“Windows 服务”的心态,它只会运行、运行和运行,不断增加成本。除非你必须拥有这个。

您想启动一个进程,让它运行,然后尽快关闭它。

现在,如果您需要它每小时运行一次,那很好。

现在,如果您需要“即时”或“尽快处理”(例如查看队列中的消息),那么您可能会付出代价并拥有一直运行的东西,因为处理这些消息比处理这些消息更重要您为正在运行的服务支付的价格。

所以从技术上讲,我喜欢这个想法

https://www.stevejgordon.co.uk/what-are-dotnet-worker-services

什么是工人服务?不需要用户交互的应用程序。使用主机来维持控制台应用程序的生命周期,直到主机收到关闭信号。将控制台应用程序转变为长期运行的服务。包括 ASP.NET Core 常见的功能,例如依赖项注入、日志记录和配置。执行定期和长时间运行的工作负载。

但在财务上,我必须用在 Azure(甚至内部部署)上运行的成本来应对这一点。

处理消息队列消息意味着 --> “是的,必须一直运行”。所以我付出了让它一直运行的代价。

如果我知道我的客户在半夜发布他们的导入文件,有一次,那么我不想支付一直运行的代价。我想要一个早上启动一次的控制台应用程序。进来,出去。尽快进行处理并退出。Kubernetes 有调度机制。

使用 Azure,不仅是技术决策,更是财务决策。

未提及:如果您的代码计划每小时运行一次,但随后开始运行时间超过一小时,则您会遇到不同的问题。Quartz.Net 是处理这些重叠问题的一种方式。

请记住,我必须对这个关于成本的争论非常坚定。大多数开发人员只是想将 windows-services 转换为 dotnet-core 并完成它。但随着越来越多的代码迁移到云中,并且云运营成本开始发挥作用,这不是长远的考虑。

聚苯乙烯

另外,请确保将所有代码移至业务层……并让这些方法中的任何一个

  • Console.App(只是普通的)

  • .NET Core 工作者服务

  • Quartz.Net 调度作业

让上面的项目成为“调用你的业务逻辑层的薄顶层”,然后你就不要把自己画成一个角落。你做的顶层越薄越好。基本上,我的控制台应用程序是

void Main(string args)
{
  //wire up IoC
  //pull out the business logic layer object from the Ioc
  //call a single method on the business logic layer
}
Run Code Online (Sandbox Code Playgroud)

一些 appsettings.json 文件是 Program.cs 文件。没有或很少。尽快将所有内容下推到业务逻辑层。


pro*_*erj 3

如果您总是要在容器中运行,那么请使用控制台应用程序。我认为作为服务运行没有固有的好处,因为容器在适当的编排(例如 Kubernetes)下应该被视为短暂的。此外,如果保持简单(即控制台),则将 .NET Core 3.1.x 应用程序作为 Linux 或 Windows 容器运行时的摩擦会更少。

另外,我会在控制台中使用以下行,以确保它与为容器分配的 CPU 配合良好:

while(true)
{
    Thread.Sleep(1 * 1000);
}
Run Code Online (Sandbox Code Playgroud)