Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does it make sense to run a c# worker service in docker?

I am developing a multi-container app in docker. One of the services is a long-running console application in C# which basically does some polling on a database and sending the data to e server. I just keep the service running by adding this statement:

while(true);

Now I'm thinking of changing this service to a .NET Core worker service (or even windows service, since I am only using windows containers on windows hosts). I have read some articles about the pros of worker services, but they seem all quite obselete when it comes to a containerized application since my container anyway is running as kind of a "background service" (and i only use one service per container/image). So my question is:

Is there any benefit or drawback when running a core worker service in docker compared to running a console app in docker?

Update: With "worker service" I refer to the new worker service template available in .NET Core 3.x: https://www.stevejgordon.co.uk/what-are-dotnet-worker-services

like image 920
Tobias von Falkenhayn Avatar asked Jul 20 '20 13:07

Tobias von Falkenhayn


People also ask

Is it better to run your AC?

Leaving your air conditioner on is actually more efficient than frequently turning it on and off. Having your AC on also allows you to better control humidity in your home throughout the day. The lower the humidity in a home, the more comfortable it feels during hot weather.

Is it better to run AC all day or just when home?

Your AC will actually run longer overall if it is left on all day instead of being shut off. If you turn it off for part of the day, it runs less and results in more energy savings for you. In almost all cases, it will save you money to shut off your AC while you are away from home.

Is air conditioning really necessary?

Air conditioning has never been considered as necessary as heating; building codes generally insist on the latter but not the former.

Is it bad to run your AC?

It's normal for an AC to run for multiple hours per day. However, there is a difference between keeping your AC on throughout the day and the compressor running all day. Once your space reaches your desired temperature, your AC system, or more specifically, the compressor, should stop running automatically.


2 Answers

In short, your happy path code will probably function "about the same".

However:

The benefit of going to the "generic host" is you get the benefit of the reusable components Microsoft has created for you......instead of rolling your own.

This means (IMHO) better code because you are not personally dealing with alot of the common issues with a long running process.

basically, you're getting a lot of plumbing code "for free" vs rolling your own implementation.

Pre 3.0/3.1 alot of this functionality was married into the asp.net namespaces. The 3.0/3.1 updates is alot of "get this into a common place for both asp.net and .net (non asp.net)" for use. Aka, demarry it from asp.net.

Setup: (a dedicated method "AddHostedService")

services.AddHostedService<MyWorkerThatImplementsIHostedService>();

So when a future developer looks at that above code, they know exactly what is going on. (vs figuring out the custom rolled implementation)

Or in a larger code example:

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

The above code ~~looks~~ asp.net'ish, but it is actually .net (non asp.net) code. Aka, you're getting improved consistency.

Shut Down:

You get all the "shut down" options built in. And these are "graceful" shut down options... which unfortunately is not usually considered for "happy path" developers. If there is any reason to jump into this mini library...having some kind of GRACEFUL exit would be it. A hard-exit might leave your processing in an unknown hard-to-trouble-shoot state.

CNLT-C

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

Kubernetes Shutdown

Microsoft has even thought out "can I delay the ultimate shutdown some"

See : How to apply HostOptions.ShutdownTimeout when configuring .NET Core Generic Host?

Here is a decent link that shows some options (Timer vs Queue vs Monitor)

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

You can also deploy your code as :

Container

Windows Service

** Linux Daemon (see https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.hosting.systemd.systemdhelpers.issystemdservice?view=dotnet-plat-ext-3.1 ) (this is usually a new concept to traditional dotnet framework developers)

Azure App Service

Oh yeah, Microsoft has even thought out "HealthChecks" for you.

https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/health-checks?view=aspnetcore-5.0#separate-readiness-and-liveness-probes-1

Bottle line, use this instead of custom rolled stuff. It is well thought out.

::::::::::::::::::::Previous Comments:::::::::::::::::::::::::::::::::(below)

...............

Long-running console application in C#

Short version:

With modern code deployment strategies, it's not just technical decisions, it's financial decisions.

Longer version:

I've had this discussion recently, as some code bases have been earmarked for "convert to dotnet core" and "how do we convert our older windows services?".

Here are my thoughts:

Philosophically.

You have to think of "where I deploy and how much does that cost?", not just the technical problem. You mention docker. But how are you doing to deploy it? Kubernetes? (AKS in azure, other?) That's an important piece of information.

IMHO: With the "cloud" or even on premise Kubernetes.... you do NOT want a "Windows service" mentality, that will just run and run and run, running up costs constantly. Unless you have to have this.

You want to startup a process, let it run, and close it down as soon as possible.

Now, if you need it to run every hour, that's fine.

Now, if you need "instant" or "as soon as possible processing", (like watching for messages on a queue), then maybe you pay the price and have something that runs all of time, because processing those messages is more important than the price you pay for the running services.

So technically, I like the idea of

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

WHAT ARE WORKER SERVICES? Applications which do not require user interaction. Use a host to maintain the lifetime of the console application until the host is signalled to shut down. Turning a console application into a long-running service. Include features common to ASP.NET Core such and dependency injection, logging and configuration. Perform periodic and long-running workloads.

But financially, I have to counter that with the cost of running on Azure (or even on premise).

Processing Message Queue messages means --> "yep, gotta run all the time". So I pay the price of having it run all the time.

If I know my client posts their import files in the middle of the night, one time, then I don't want to pay that price of always running. I want a console app that fires once in the morning. Get in, get out. Do the processing as quick as possible and get out. Kubernetes has scheduling mechanisms.

With Azure, it's not just technical decisions, it's financial decisions.

Not mentioned: if your code is scheduled to run every hour, but then starts taking longer than hour to run, you have different issues. Quartz.Net is one way to deal with these overlap issues.

Keep in mind, I had to really be firm about this argument about cost. Most developers just wanted to convert the windows-services to dotnet-core and be done with it. But that is not long term thinking as more code moves to the cloud and the cost of cloud operation come into play.

PS

Also, make sure you move all your code DOWN INTO A BUSINESS LAYER........and let any of these methods

  • Console.App (just regular one)

  • .NET Core worker service

  • Quartz.Net schedule job

Let the above items be "thin top layer that call your business logic layer", and then you don't paint yourself into a corner. The thinner you make that top layer, the better. Basically, my console-apps are

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
}

and some appsettings.json files were Program.cs sits. Nothing or very little else. Push everything down to the business logic layer as soon as possible.

like image 162
granadaCoder Avatar answered Oct 16 '22 11:10

granadaCoder


If you are always going to run in a container, then go with a console app. I see no inherent benefit of running as a service since containers, under proper orchestration such as Kubernetes, should be considered ephemeral. Also, you will have less friction in running your .NET Core 3.1.x application as a Linux or Windows container if you keep it simple i.e. console.

Also, I would use the following line in your console to ensure it plays nice with the allocated CPU for the container:

while(true)
{
    Thread.Sleep(1 * 1000);
}
like image 3
programmerj Avatar answered Oct 16 '22 11:10

programmerj