Closed igor-moskvitin closed 5 years ago
The method DoWork() should be call like: await Task.Run(this.DoWork);
@yuexuanwo, it doesnt matter how i call DoWork()
public async Task StartAsync(CancellationToken cancellationToken)
{
await Task.Run(DoWork);
}
or
public Task StartAsync(CancellationToken cancellationToken)
{
DoWork();
return Task.CompletedTask;
}
in output i can see only messages from first registerd service: like "ServiceA" if
services.AddSingleton<IHostedService, ServiceA>();
services.AddSingleton<IHostedService, ServiceB>();
and "ServiceB" if
services.AddSingleton<IHostedService, ServiceB>();
services.AddSingleton<IHostedService, ServiceA>();
StartAsync needs to return and neither DoWork()
nor await Task.Run(DoWork)
allow StartAsync to complete.
Task.Run(DoWork)
without await will work.
Hi @igor-moskvitin, @xygon, Thanks for your feedback.
It's just a little bit more involved.
To properly handle graceful cancellation you have to implement your services using the pattern shown in the BackgroundService class in the article.
Using the above pattern, DoWork
is renamed to ExecuteAsync
, but it's just the same!
However, since almost all of the code in BackgroundService is boilerplate, you'd be better off just inheriting your services from BackgroundService.
This way the final code gets pretty simple:
public class Program
{
private static async Task Main(string[] args)
{
Console.WriteLine("Hosted services demo");
Console.WriteLine();
var builder = new HostBuilder()
.ConfigureServices(services =>
{
services.AddSingleton<IHostedService, ServiceA>();
services.AddSingleton<IHostedService, ServiceB>();
});
await builder.RunConsoleAsync();
}
}
public class ServiceA : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
stoppingToken.Register(() => Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} - Stopping Service A..."));
while (!stoppingToken.IsCancellationRequested)
{
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} - Service A running (thread {Thread.CurrentThread.ManagedThreadId})...");
await Task.Delay(2200, stoppingToken);
}
}
}
public class ServiceB : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
stoppingToken.Register(() => Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} - Stopping Service B..."));
while (!stoppingToken.IsCancellationRequested)
{
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} - Service B running (thread {Thread.CurrentThread.ManagedThreadId})...");
await Task.Delay(1500, stoppingToken);
}
}
}
And you get the output you expect:
11:00:07.149 - Service A running (thread 1)...
11:00:07.173 - Service B running (thread 1)...
Application started. Press Ctrl+C to shut down.
Hosting environment: Production
Content root path: C:\Users\Miguel\source\repos\explore-hosted-services\HostedServices\bin\Debug\netcoreapp2.2\
11:00:08.692 - Service B running (thread 4)...
11:00:09.379 - Service A running (thread 5)...
11:00:10.192 - Service B running (thread 4)...
11:00:11.595 - Service A running (thread 4)...
11:00:11.692 - Service B running (thread 5)...
11:00:14.539 - Service B running (thread 6)...
11:00:15.241 - Service A running (thread 6)...
11:00:15.983 - Stopping Service B...
11:00:16.021 - Stopping Service A...
In the above example the stopping was started with Ctrl+C.
Hope this helps.
@mvelosop , thanks a lot!
If i try to register two or more services, only one could work properly. For example:
Implementations are simplest as possible:
and
In output getting messages only from ServiceA
Document Details
⚠ Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.