{"id":8766,"date":"2017-11-18T14:03:20","date_gmt":"2017-11-18T22:03:20","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/cesardelatorre\/?p=8766"},"modified":"2019-03-18T22:30:31","modified_gmt":"2019-03-19T05:30:31","slug":"implementing-background-tasks-in-microservices-with-ihostedservice-and-the-backgroundservice-class-net-core-2-x","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/cesardelatorre\/implementing-background-tasks-in-microservices-with-ihostedservice-and-the-backgroundservice-class-net-core-2-x\/","title":{"rendered":"Implementing background tasks in .NET Core 2.x webapps or microservices with IHostedService and the BackgroundService class"},"content":{"rendered":"<p>Background tasks and scheduled jobs are something you might need to implement, eventually, in a microservice based application or in any kind of application. The difference when using a microservices architecture is that you can implement a single microservice process\/container for hosting these background tasks so you can scale it down\/up as you need or you can even make sure that it runs a single instance of that microservice process\/container.\nFrom a generic point of view, in .NET Core we called these type of tasks as Hosted Services, because they are services\/logic that you host within your host\/application\/microservice. Note that in this case, the hosted service simply means a class with the background task logic.\nSince .NET Core 2.0, the framework provides a new interface named IHostedService helping you to easily implement hosted services. The basic idea is that you can register multiple background tasks (hosted services), that run in the background while your web host or host is running, as shown in the following image.<\/p>\n<p><img decoding=\"async\" class=\"alignnone size-large wp-image-8775\" src=\"http:\/\/devblogs.microsoft.com\/cesardelatorre\/wp-content\/uploads\/sites\/32\/2017\/11\/image2610-1024x498.png\" alt=\"\" width=\"1024\" height=\"498\" srcset=\"https:\/\/devblogs.microsoft.com\/cesardelatorre\/wp-content\/uploads\/sites\/32\/2017\/11\/image2610-1024x498.png 1024w, https:\/\/devblogs.microsoft.com\/cesardelatorre\/wp-content\/uploads\/sites\/32\/2017\/11\/image2610-300x146.png 300w, https:\/\/devblogs.microsoft.com\/cesardelatorre\/wp-content\/uploads\/sites\/32\/2017\/11\/image2610-768x374.png 768w, https:\/\/devblogs.microsoft.com\/cesardelatorre\/wp-content\/uploads\/sites\/32\/2017\/11\/image2610.png 1936w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/p>\n<p>Note the difference made between WebHost and Host.<\/p>\n<p>A WebHost (base class implementing IWebHost) in ASP.NET Core 2.0 is the infrastructure artifact you use to provide Http server features to your process, such as if you are implementing an MVC web app or Web API service. It provides all the new infrastructure goodness in ASP.NET Core, enabling you to use dependency injection, insert middlewares in the Http pipeline, etc. and precisely use these IHostedServices for background tasks.<\/p>\n<p>A Host (base class implementing IHost), however, is something new in .NET Core 2.1 (as of the writing of this text, not yet released). Basically, a Host allows you to have a similar infrastructure than what you have with WebHost (dependency injection, hosted services, etc.), but in this case, you just want to have a simple and lighter process as the host, with nothing related to MVC, Web API or Http server features.<\/p>\n<p>Therefore, you can choose and either create a specialized host-process to handle the hosted services and nothing else, such a microservice made just for hosting the IHostedServices, or you can alternatevely extend an existing ASP.NET Core WebHost, such as an existing ASP.NET Core Web API or MVC app. Each approach has pros and cons depending on your business and scalability needs.<\/p>\n<h2>Registering hosted services in your WebHost or Host<\/h2>\n<p>Let\u2019s drill down further on the IHostedService interface since its usage is pretty similar in a WebHost or in a Host.<\/p>\n<p>SignalR is one example of an artifact using hosted services, but you can also use it for much simpler things like:<\/p>\n<ul>\n<li>A background task polling a database looking for changes<\/li>\n<li>A scheduled task updating some cache periodically.<\/li>\n<li>An implementation of QueueBackgroundWorkItem that allows a task to be executed on a background thread.<\/li>\n<li>Processing messages from a message queue in the background of a web app while sharing common services such as ILogger.<\/li>\n<\/ul>\n<p>You can basically offload any of those actions to a background task based on IHostedService.<\/p>\n<p>The way you add one or multiple IHostedServices into your WebHost or Host is by registering them up through the standard DI (dependency injection) in an ASP.NET Core WebHost (or in a Host in .NET Core 2.1). Basically, you have to register the hosted services within the familiar ConfigureServices() method of the Startup class, as in the following code from a typical ASP.NET WebHost.<\/p>\n<pre class=\"lang:default decode:true\">public IServiceProvider ConfigureServices(IServiceCollection services)\r\n{\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n\u00a0\u00a0\u00a0 \/\/Other DI registrations;\r\n    \/\/...\r\n\u00a0\u00a0\u00a0 \/\/ Register Hosted Services\r\n\u00a0\u00a0\u00a0 services.AddSingleton&lt;IHostedService, GracePeriodManagerService&gt;();\r\n\u00a0\u00a0\u00a0 services.AddSingleton&lt;IHostedService, MyHostedServiceB&gt;();\r\n\u00a0\u00a0\u00a0 services.AddSingleton&lt;IHostedService, MyHostedServiceC&gt;();\r\n\u00a0\u00a0\u00a0 \/\/...\r\n}<\/pre>\n<p>In that code, the <strong>GracePeriodManagerService<\/strong> hosted service is real code from the Ordering business microservice in eShopOnContainers, while the other two are just two additional samples.<\/p>\n<p>The IHostedService background task execution is coordinated with the lifetime of the application (host or microservice, for that matter). You register tasks when the application starts and you have the opportunity to do some graceful action or clean-up when the application is shutting down.<\/p>\n<p>Without using IHostedService, you could always start a background thread to run any task. The difference is precisely at the app\u2019s shutdown time when that thread would simply be killed without having the opportunity to run graceful clean-up actions.<\/p>\n<h2>The IHostedService interface<\/h2>\n<p>When you register an IHostedService, .NET Core will call the <strong>StartAsync()<\/strong> and <strong>StopAsync()<\/strong> methods of your IHostedService type during application start and stop respectively. Specifically, start is called after the server has started and IApplicationLifetime.ApplicationStarted is triggered.<\/p>\n<p>The IHostedService as defined in .NET Core, looks like the following.<\/p>\n<pre class=\"lang:default decode:true\">namespace Microsoft.Extensions.Hosting\r\n{\r\n\u00a0\u00a0\u00a0 \/\/\r\n\u00a0\u00a0\u00a0 \/\/ Summary:\r\n\u00a0\u00a0\u00a0 \/\/\u00a0\u00a0\u00a0\u00a0 Defines methods for objects that are managed by the host.\r\n\u00a0\u00a0\u00a0 public interface IHostedService\r\n\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Summary:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Triggered when the application host is ready to start the service.\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Task StartAsync(CancellationToken cancellationToken);\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Summary:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Triggered when the application host is performing a graceful shutdown.\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Task StopAsync(CancellationToken cancellationToken);\r\n\u00a0\u00a0\u00a0 }\r\n}<\/pre>\n<p>As you can imagine, you can create multiple implementations of IHostedService and register them at the ConfigureService() method into the DI container, as shown previously. All those hosted services will be started and stopped along with the application\/microservice.<\/p>\n<p>As a developer, you are responsible for handling the stopping action or your services when StopAsync() method is triggered by the host.<\/p>\n<h2>Implementing IHostedService with a custom hosted service class deriving from the BackgroundService base class<\/h2>\n<p>You could go ahead and create you custom hosted service class from scratch and implement the IHostedService, as you need to do when using .NET Core 2.0.<\/p>\n<p>However, since most background tasks will need pretty similar needs in regard to the cancellation tokens management and other tipical operations, .NET Core 2.1 is providing a very convenient abstract base class you can derive from, named BackgroundService.<\/p>\n<p>That class provides the main work needed to set up the background task. Note that this class will come in the .NET Core 2.1 library so you don\u2019t need to write it.<\/p>\n<p>However, as of the time of this writing, .NET Core 2.1 has not been released. Therefore, in eShopOnContainers which is currently using .NET Core 2.0, we are just \u201cstealing\u201d that class from the open-source repo because it is compatible with the current IHostedService interface in .NET Core 2.0. Kudos to David Fowler who wrote this convenient class. \ud83d\ude42<\/p>\n<p>When .NET Core 2.1 is released, you&#8217;ll just need to point to the right NuGet package.<\/p>\n<p>The next code is the abstract BackgroundService base class as implemented in .NET Core 2.1.<\/p>\n<pre class=\"lang:default decode:true\">\/\/ Copyright (c) .NET Foundation. Licensed under the Apache License, Version 2.0.\r\n\/\/\/ &lt;summary&gt;\r\n\/\/\/ Base class for implementing a long running &lt;see cref=\"IHostedService\"\/&gt;.\r\n\/\/\/ &lt;\/summary&gt;\r\npublic abstract class BackgroundService : IHostedService, IDisposable\r\n{\r\n\u00a0\u00a0\u00a0 private Task _executingTask;\r\n\u00a0\u00a0\u00a0 private readonly CancellationTokenSource _stoppingCts =\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 new CancellationTokenSource();\r\n\r\n\u00a0\u00a0\u00a0 protected abstract Task ExecuteAsync(CancellationToken stoppingToken);\r\n\r\n\u00a0\u00a0\u00a0 public virtual Task StartAsync(CancellationToken cancellationToken)\r\n\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Store the task we're executing\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 _executingTask = ExecuteAsync(_stoppingCts.Token);\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ If the task is completed then return it,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ this will bubble cancellation and failure to the caller\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (_executingTask.IsCompleted)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return _executingTask;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Otherwise it's running\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return Task.CompletedTask;\r\n\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0 public virtual async Task StopAsync(CancellationToken cancellationToken)\r\n\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Stop called without start\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (_executingTask == null)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 try\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Signal cancellation to the executing method\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 _stoppingCts.Cancel();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 finally\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Wait until the task completes or the stop token triggers\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0cancellationToken));\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0 public virtual void Dispose()\r\n\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 _stoppingCts.Cancel();\r\n\u00a0\u00a0\u00a0 }\r\n}\r\n<\/pre>\n<p>When deriving from the previous abstract base class, thanks to that inherited implementation, you just need to implement the <strong>ExecuteAsync() <\/strong>method in your own custom hosted service class, as in the following simplified code from eShopOnContainers which is polling a database and publishing integration events into the Event Bus when needed.<\/p>\n<pre class=\"lang:default decode:true\">public class GracePeriodManagerService\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : BackgroundService\r\n{\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n\u00a0\u00a0\u00a0 private readonly ILogger&lt;GracePeriodManagerService&gt; _logger;\r\n\u00a0\u00a0\u00a0 private readonly OrderingBackgroundSettings _settings;\r\n\r\n\u00a0\u00a0\u00a0 private readonly IEventBus _eventBus;\r\n\r\n\u00a0\u00a0\u00a0 public GracePeriodManagerService(IOptions&lt;OrderingBackgroundSettings&gt; settings,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 IEventBus eventBus,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ILogger&lt;GracePeriodManagerService&gt; logger)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/Constructor\u2019s parameters validations...\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 protected override async Task ExecuteAsync(CancellationToken stoppingToken)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 _logger.LogDebug($\"GracePeriodManagerService is starting.\");\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 stoppingToken.Register(() =&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 _logger.LogDebug($\" GracePeriod background task is stopping.\"));\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 while (!stoppingToken.IsCancellationRequested)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 _logger.LogDebug($\"GracePeriod task doing background work.\");\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ This eShopOnContainers method is quering a database table \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ and publishing events into the Event Bus (RabbitMS \/ ServiceBus)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 CheckConfirmedGracePeriodOrders();\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 await Task.Delay(_settings.CheckUpdateTime, stoppingToken);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 _logger.LogDebug($\"GracePeriod background task is stopping.\");\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 protected override async Task StopAsync (CancellationToken stoppingToken)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Run your graceful clean-up actions\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n}<\/pre>\n<p>In this specific case for eShopOnContainers, it is executing an application method which is quering a database table looking for orders with a specific state and when applying changes, it is publishing integration events through the event bus (underneath it can be using RabbitMQ or Azure Service Bus).<\/p>\n<p>Of course, you could run any other business background task, instead.<\/p>\n<p>By default, the cancellation token is set with a 5 second timeout, although you can change that value when building your WebHost using the UseShutdownTimeout extension of the IWebHostBuilder. This means that our service is expected to cancel within 5 seconds otherwise it will be more abruptly killed.<\/p>\n<p>The following code would be changing that time to 10 seconds.<\/p>\n<pre class=\"lang:default decode:true\">WebHost.CreateDefaultBuilder(args)\r\n\r\n\u00a0\u00a0\u00a0 .UseShutdownTimeout(TimeSpan.FromSeconds(10))\r\n\r\n\u00a0\u00a0\u00a0 ...<\/pre>\n<h4>Summary class diagram<\/h4>\n<p>The following image X-X shows a visual summary of the classes and interfaced involved when implementing IHostedServices.<\/p>\n<p><img decoding=\"async\" class=\"alignnone size-large wp-image-8795\" src=\"http:\/\/devblogs.microsoft.com\/cesardelatorre\/wp-content\/uploads\/sites\/32\/2017\/11\/image2711-1024x513.png\" alt=\"\" width=\"1024\" height=\"513\" srcset=\"https:\/\/devblogs.microsoft.com\/cesardelatorre\/wp-content\/uploads\/sites\/32\/2017\/11\/image2711-1024x513.png 1024w, https:\/\/devblogs.microsoft.com\/cesardelatorre\/wp-content\/uploads\/sites\/32\/2017\/11\/image2711-300x150.png 300w, https:\/\/devblogs.microsoft.com\/cesardelatorre\/wp-content\/uploads\/sites\/32\/2017\/11\/image2711-768x385.png 768w, https:\/\/devblogs.microsoft.com\/cesardelatorre\/wp-content\/uploads\/sites\/32\/2017\/11\/image2711.png 1791w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/p>\n<h4>Deployment considerations and takeaways<\/h4>\n<p>It is important to note that the way you deploy your ASP.NET Core WebHost or .NET Core Host might impact the final solution. For instance, if you deploy your WebHost on IIS or a regular Azure App Service, your host can be shut down because of app pool recycles. But if you are deploying your host as a container into an orchestrator like <strong>Kubernetes<\/strong> or <strong>Service Fabric<\/strong>, you can control the assured number of live instances of your host. In addition, you could consider other approaches in the cloud especially made for these scenarios, like <strong>Azure Functions<\/strong>.<\/p>\n<p>But even for a WebHost deployed into an app pool, there are scenarios like repopulating or flushing application\u2019s in-memory cache, that would be still applicable.<\/p>\n<p>The IHostedService interface provides a convenient way to start background tasks in an ASP.NET Core web application (in .NET Core 2.0) or in any process\/host (starting in .NET Core 2.1 with IHost).<\/p>\n<p>Its main benefit is the opportunity you get with the graceful cancellation to clean-up code of your background tasks when the host itself is shutting down.<\/p>\n<p>&nbsp;<\/p>\n<p><strong>UPDATED &#8211; January 2nd 2018:<\/strong><\/p>\n<p>The following page is the official related info, similar to this blog post but reviewed and with additional\/minor updates:<\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/standard\/microservices-architecture\/multi-container-microservice-net-applications\/background-tasks-with-ihostedservice\">https:\/\/docs.microsoft.com\/en-us\/dotnet\/standard\/microservices-architecture\/multi-container-microservice-net-applications\/background-tasks-with-ihostedservice\u00a0<\/a><\/p>\n<p>&nbsp;<\/p>\n<p>Check it out and send us feedback! \ud83d\ude42<\/p>\n<p>&nbsp;<\/p>\n<p><strong>UPDATED &#8211; Feb. 2018<\/strong><\/p>\n<p>Additional References:<\/p>\n<p>&#8211; <a href=\"https:\/\/pgroene.wordpress.com\/2018\/02\/21\/asp-net-core-background-processing\/\">Run background processes with the IHostedService and how to inject your services with dependency injection<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Background tasks and scheduled jobs are something you might need to implement, eventually, in a microservice based application or in any kind of application. The difference when using a microservices architecture is that you can implement a single microservice process\/container for hosting these background tasks so you can scale it down\/up as you need or [&hellip;]<\/p>\n","protected":false},"author":362,"featured_media":12526,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[8,21,53],"class_list":["post-8766","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cesardelatorre","tag-net-core","tag-asp-net-core","tag-ihostedservice"],"acf":[],"blog_post_summary":"<p>Background tasks and scheduled jobs are something you might need to implement, eventually, in a microservice based application or in any kind of application. The difference when using a microservices architecture is that you can implement a single microservice process\/container for hosting these background tasks so you can scale it down\/up as you need or [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/cesardelatorre\/wp-json\/wp\/v2\/posts\/8766","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/cesardelatorre\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/cesardelatorre\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cesardelatorre\/wp-json\/wp\/v2\/users\/362"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cesardelatorre\/wp-json\/wp\/v2\/comments?post=8766"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/cesardelatorre\/wp-json\/wp\/v2\/posts\/8766\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cesardelatorre\/wp-json\/wp\/v2\/media\/12526"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/cesardelatorre\/wp-json\/wp\/v2\/media?parent=8766"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cesardelatorre\/wp-json\/wp\/v2\/categories?post=8766"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cesardelatorre\/wp-json\/wp\/v2\/tags?post=8766"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}