question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

IHostedService with Monitor produces System.OperationCanceledException

See original GitHub issue

Describe the bug

IHostedService with Monitor produces System.OperationCanceledException on some occasions but not on all occasions on termination.

To Reproduce

  1. Using Target Framework netcoreapp3.1
  2. Using Microsoft.Extensions.Hosting version 3.1.2
  3. Run this code:
public class SyncService : IHostedService, IDisposable
{
	private static object _workerMonitor = new object();
	private Timer _timer;

	public Task StartAsync(CancellationToken cancellationToken)
	{
		_timer = new Timer(Callback, null, TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(5));
		return Task.CompletedTask;
	}

	public Task StopAsync(CancellationToken cancellationToken)
	{
		Console.WriteLine("Stopping");
		_timer?.Change(0, 0);
		Monitor.Enter(_workerMonitor);
		Console.WriteLine("Stopped");
		return Task.CompletedTask;
	}

	public void Dispose()
	{
		Console.WriteLine("Disposing");
		_timer?.Dispose();
		Console.WriteLine("Disposed");
	}

	private void Callback(object state)
	{
		if (Monitor.TryEnter(_workerMonitor))
			try
			{
				Console.WriteLine("Cycle Start");
				Thread.Sleep(10000);
				Console.WriteLine("Cycle End");
			}
			catch (Exception e)
			{
				Console.WriteLine("Fatal Exception" + e);
			}
			finally
			{
				Monitor.Exit(_workerMonitor);
				Console.WriteLine("Exited");
			}
	}
}

class Program
{
	static void Main(string[] args)
	{
		try
		{
			var builder = new HostBuilder()
						  .ConfigureServices(collection => collection.AddHostedService<SyncService>())
				.Build();

			builder.Run();
		}
		catch (Exception ex)
		{
			Console.WriteLine(ex);
		}
	}
}

  1. Terminate the program using CTRL+C. This triggers the StopAsync method.
  2. See error

Expected behavior

The program should terminate without error message.

Actual behavior

The program terminates sometimes with error message sometimes without. I noticed that the exception shows up if I hit CTRL+C immediately after the “Cycle Start” message. If I wait for about 6/7 seconds the exception isn’t thrown.

Console Output if error shows up:

Cycle Start
Stopping
Cycle End
Exited
Stopped
Disposing
Disposed
System.OperationCanceledException: The operation was canceled.
   at System.Threading.CancellationToken.ThrowOperationCanceledException()
   at Microsoft.Extensions.Hosting.Internal.Host.StopAsync(CancellationToken cancellationToken)
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.WaitForShutdownAsync(IHost host, CancellationToken token)
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.Run(IHost host)
   at ConsoleApp1.Program.Main(String[] args) in C:\Users\...\ConsoleApp1\ConsoleApp1\Program.cs:line 67

Console output without error (expected):

Cycle Start
Stopping
Cycle End
Exited
Stopped
Disposing
Disposed

Additional context

Output of dotnet --info .NET Core SDK (reflecting any global.json): Version: 3.1.101 Commit: b377529961

Runtime Environment: OS Name: Windows OS Version: 10.0.17763 OS Platform: Windows RID: win10-x64 Base Path: C:\Program Files\dotnet\sdk\3.1.101\

Host (useful for support): Version: 3.1.1 Commit: a1388f194c

.NET Core SDKs installed: 2.2.402 [C:\Program Files\dotnet\sdk] 3.1.101 [C:\Program Files\dotnet\sdk]

.NET Core runtimes installed: Microsoft.AspNetCore.All 2.1.15 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All] Microsoft.AspNetCore.All 2.2.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All] Microsoft.AspNetCore.App 2.1.15 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 2.2.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 3.1.1 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.NETCore.App 2.1.15 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 2.2.7 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 3.1.1 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.WindowsDesktop.App 3.1.1 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:2
  • Comments:5

github_iconTop GitHub Comments

1reaction
analogrelaycommented, Mar 6, 2020

It looks like we don’t have an extension method for it on IHostBuilder. Might just be something we missed when moving from WebHost to GenericHost, or it might have been an intentional omission. Feel free to file a new bug asking for the extension method to be supported on IHostBuilder! If there’s a reason we omitted it, we’ll let you know in the issue, but there’s no harm in suggesting it!

0reactions
klysecommented, Mar 6, 2020

This solved my actual problem because I’m using a WebHost.

But my example uses a HostBuilder. Therefore UseShutdownTimeout is not available as a extension method. So I did some digging in the framework and found that the UseShutdownTimeout is eventually just a configuration with the keyword shutdownTimeoutSeconds

Link to code: https://github.com/dotnet/aspnetcore/blob/8cba1cbb231b37d56c352fad196619b11c5c6613/src/Hosting/Abstractions/src/HostingAbstractionsWebHostBuilderExtensions.cs#L179-L182

Then I refactored my create HostBuilder code:

var builder = new HostBuilder()
	.ConfigureAppConfiguration(configurationBuilder =>
	{
		configurationBuilder.AddInMemoryCollection(new Dictionary<string, string>
		{
			{ "shutdownTimeoutSeconds", "600" }
		});
	})
	.ConfigureServices(collection => collection.AddHostedService<SyncService>())
	.Build();

But this ain’t working… Just out of curiosity (and because I think somebody else might stumble over the same issue) how could I solve this when I have a HostBuilder?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Lifecycle of Generic Host Background Services
I decided to investigate the interactions between the Generic Host, IHostedService instances, and BackgroundService in particular, and decided I ...
Read more >
NET Core BackgroundService: "A task was canceled." Error
Hello i developed BackgroundService which is to monitor Oracle Database and when new records inserted into source table, copy records into ...
Read more >
ASP.NET Core IHostedService, BackgroundService and error ...
An IHostedService is a service that allows for running code before the rest of your ASP.NET Core application starts. The interface has two...
Read more >
Working with Apache Kafka in ASP.NET 6 Core
Kafka is an open-source high throughput, low latency messaging system for distributed applications. Joydip shows you how it's what you've been waiting for....
Read more >
A Professional ASP.NET Core API - Background Task
The cancellation token is triggered when IHostedService.StopAsync is called. Your implementation of ExecuteAsync should finish promptly when the ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found