Why is this CancellationToken getting cancelled? - c#

It seems like right after I call my first async method (GetBar() in this example), the CancellationToken's IsCancellationRequested is set to true, but I don't want that and don't understand why it's happening.
This is in an Azure Cloud Service worker role, if that matters.
public class WorkerRole : RoleEntryPoint
{
private CancellationTokenSource cancellationTokenSource;
private Task runTask;
public override void Run()
{
this.cancellationTokenSource = new CancellationTokenSource();
this.runTask = Task.Run(() => Foo.Bar(this.cancellationTokenSource.Token), this.cancellationTokenSource.Token);
}
public override void OnStop()
{
this.cancellationTokenSource.Cancel();
try
{
this.runTask.Wait();
}
catch (Exception e)
{
Logger.Error(e, e.Message);
}
base.OnStop();
}
// ... OnStart omitted
}
public static class Foo
{
public static async Bar(CancellationToken token)
{
while (true)
{
try
{
token.ThrowIfCancellationRequested();
var bar = await FooService.GetBar().ConfigureAwait(false);
// Now token.IsCancellationRequested == true. Why? The above call does not take the token as input.
}
catch (OperationCanceledException)
{
// ... Handling
}
}
}
}
I've successfully used CancellationTokens once before in another project and I use a similar setup here. The only difference I'm aware of is that this is in an Azure Cloud Service. Any idea why IsCancellationRequested is getting set to true?

It appears OnStop was called while you where awaiting for FooService.GetBar() to complete. Perhaps add some form of logging to see if OnStop is called between the token.ThrowIfCancellationRequested(); and after the var bar = await ... returns to confirm.
That is what is causing the token to be canceled.
To solve the problem you need to make sure the overridden Run method does not return till the work is complete.
public override void Run()
{
this.cancellationTokenSource = new CancellationTokenSource();
this.runTask = Task.Run(() => Foo.Bar(this.cancellationTokenSource.Token), this.cancellationTokenSource.Token);
this.runTask.Wait(); //You may need a try/catch around it
}

Related

C# DotNet 3.x Multiple BackgroudServices do not run consistently

I have a SignalR app in DotNet 3.1, kind-of a large chat app, and I am trying to add two BackgroundServices.
The BackgroundServices are setup to run for as long as the ASP.NET app runs.
The first BackgroundService has a very fast main loop (50 ms) and seems to work well.
The second BackgroundService has a much longer main loop (1000 ms) and seems to start randomly, stop executing randomly, and then re-starts executing again ... randomly. It is almost like the second bot is going to sleep, for a long period of time (30 to 90 seconds) and then wakes up again with the object state preserved.
Both BackgroundServices have the same base code with different Delays.
Is it possible to have multiple, independent, non-ending, BackgroundServices? If so, then what am I doing wrong?
I have the services registered like this ...
_services.AddSimpleInjector(_simpleInjectorContainer, options =>
{
options.AddHostedService<SecondaryBackgroundService>();
options.AddHostedService<PrimaryBackgroundService>();
// AddAspNetCore() wraps web requests in a Simple Injector scope.
options.AddAspNetCore()
// Ensure activation of a specific framework type to be created by
// Simple Injector instead of the built-in configuration system.
.AddControllerActivation()
.AddViewComponentActivation()
.AddPageModelActivation()
.AddTagHelperActivation();
});
And I have two classes (PrimaryBackgroundService/SecondaryBackgroundService) that have this ...
public class SecondaryBackgroundService : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
{
await Task.Factory.StartNew(async () =>
{
// loop until a cancalation is requested
while (!cancellationToken.IsCancellationRequested)
{
//await Task.Delay(TimeSpan.FromMilliseconds(50), cancellationToken);
await Task.Delay(TimeSpan.FromMilliseconds(1000), cancellationToken);
try
{
await _doWorkDelegate();
}
catch (Exception ex)
{
}
}
}, cancellationToken);
}
}
Should I setup a single BackgroundService that spins off two different Tasks; in their own threads? Should I be using IHostedService instead?
I need to make sure that the second BackgroundService runs every second. Also, I need to make sure that the second BackgroundService never impacts the faster running primary BackgroundService.
UPDATE:
I changed the code to use a Timer, as suggested, but now I am struggling with calling an async Task from a Timer event.
Here is the class I created with the different options that work and do not work.
// used this as the base: https://github.com/aspnet/Hosting/blob/master/src/Microsoft.Extensions.Hosting.Abstractions/BackgroundService.cs
public abstract class RecurringBackgroundService : IHostedService, IDisposable
{
private Timer _timer;
protected int TimerIntervalInMilliseconds { get; set; } = 250;
// OPTION 1. This causes strange behavior; random starts and stops
/*
protected abstract Task DoRecurringWork();
private async void OnTimerCallback(object notUsedTimerState) // use "async void" for event handlers
{
try
{
await DoRecurringWork();
}
finally
{
// do a single call timer pulse
_timer.Change(this.TimerIntervalInMilliseconds, Timeout.Infinite);
}
}
*/
// OPTION 2. This causes strange behavior; random starts and stops
/*
protected abstract Task DoRecurringWork();
private void OnTimerCallback(object notUsedTimerState)
{
try
{
var tf = new TaskFactory(System.Threading.CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, TaskScheduler.Default);
tf.StartNew(async () =>
{
await DoRecurringWork();
})
.Unwrap()
.GetAwaiter()
.GetResult();
}
finally
{
// do a single call timer pulse
_timer.Change(this.TimerIntervalInMilliseconds, Timeout.Infinite);
}
}
*/
// OPTION 3. This works but requires the drived to have "async void"
/*
protected abstract void DoRecurringWork();
private void OnTimerCallback(object notUsedTimerState)
{
try
{
DoRecurringWork(); // use "async void" in the derived class
}
finally
{
// do a single call timer pulse
_timer.Change(this.TimerIntervalInMilliseconds, Timeout.Infinite);
}
}
*/
// OPTION 4. This works just like OPTION 3 and allows the drived class to use a Task
protected abstract Task DoRecurringWork();
protected async void DoRecurringWorkInternal() // use "async void"
{
await DoRecurringWork();
}
private void OnTimerCallback(object notUsedTimerState)
{
try
{
DoRecurringWork();
}
finally
{
// do a single call timer pulse
_timer.Change(this.TimerIntervalInMilliseconds, Timeout.Infinite);
}
}
public virtual Task StartAsync(CancellationToken cancellationToken)
{
// https://stackoverflow.com/questions/684200/synchronizing-a-timer-to-prevent-overlap
// do a single call timer pulse
_timer = new Timer(OnTimerCallback, null, this.TimerIntervalInMilliseconds, Timeout.Infinite);
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
try { _timer.Change(Timeout.Infinite, 0); } catch {; }
return Task.CompletedTask;
}
public void Dispose()
{
try { _timer.Change(Timeout.Infinite, 0); } catch {; }
try { _timer.Dispose(); } catch {; }
}
}
Is OPTION 3 and/or OPTION 4 correct?
I have confirmed that OPTION 3 and OPTION 4 are overlapping. How can I stop them from overlapping? (UPDATE: use OPTION 1)
UPDATE
Looks like OPTION 1 was correct after all.
Stephen Cleary was correct. After digging and digging into the code I did find a Task that was stalling the execution under the _doWorkDelegate() method. The random starts and stops was caused by an HTTP call that was failing. Once I fixed that (with a fire-and-forget) OPTION 1 started working as expected.
I would recommend writing two timed background tasks as shown in the documentation
Timed background tasks documentation
then they are independent and isolated.
public class PrimaryBackgroundService : IHostedService, IDisposable
{
private readonly ILogger<PrimaryBackgroundService> _logger;
private Timer _timer;
public PrimaryBackgroundService(ILogger<PrimaryBackgroundService> logger)
{
_logger = logger;
}
public Task StartAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("PrimaryBackgroundService StartAsync");
TimeSpan waitTillStart = TimeSpan.Zero;
TimeSpan intervalBetweenWork = TimeSpan.FromMilliseconds(50);
_timer = new Timer(DoWork, null, waitTillStart, intervalBetweenWork);
return Task.CompletedTask;
}
private void DoWork(object state)
{
_logger.LogInformation("PrimaryBackgroundService DoWork");
// ... do work
}
public Task StopAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("PrimaryBackgroundService is stopping.");
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
public void Dispose()
{
_timer?.Dispose();
}
}
create the SecondaryBackgroundService using similar code and register them as you did before
options.AddHostedService<SecondaryBackgroundService>();
options.AddHostedService<PrimaryBackgroundService>();
Note that if you want to use any dependency injection then you have to inject IServiceScopeFactory into the background service constructor and call scopeFactory.CreateScope()

(A)wait for class to finish instantiate

I try to wait for the class to be finished with instantiate.
My architecture is the following. Cook is inheriade from CookChief.
And if I instantiate cook, CookChief is creating himself, but CookChief is calling 1 other class named Cookhelper the cookhelper is waiting for a input and for this input method i want to wait in Cook.
The thing is iam creating this in MVVM Galasoft and my entry point is the CookViewmodel, with a relaycommand.
In the code below you can see my architecture. To say it short I want to wait until this bool processed = await Task.Run(() => ValidateForDeviceId()); is finished.
My first step was to outsource the constructer of each class. And create a init method.
This is my code:
public CookViewModel()
{
startCookButtonCommand = new RelayCommand(Cook);
}
private async Task Cook()
{
cook.Init();
}
public class Cook : CookChief
{
public Cook()
{
}
public async Task Init()
{
await this.CookChiefInit();
//here I want to wait until CookChiefInit is finished
Cooking();
}
public void Cooking()
{
MessageBox.Show("Input received");
}
}
Now the Cookchief:
public Cookchief()
{
}
protected async Task CookchiefInit()
{
this.Cookhelper = new Cookhelper();
Cookhelper.CookHelperInit();
}
And in the CookHelper we do this:
public CookHelper()
{
}
public void CookHelperInit()
{
this.driverWindow = new DriverWindow();
startProc();
}
private async void startProc()
{
ShowOrCloseDriverWindow(true);
//this is the task what we wait for before we can repeat
bool processed = await Task.Run(() => ValidateForDeviceId());
if(processed)
{
ShowOrCloseDriverWindow(false);
}
else
{
MessageBox.Show("DriverError");
}
}
private bool ValidateForDeviceId()
{
for (; ; )
{
this.deviceId = Input.deviceId;
if (deviceId > 0)
{
break;
}
}
return true;
}
Per the discussion in the comments, the problem here was that the initialization routine mixed synchronous and asynchronous methods and calls. Additionally, some async methods were called without the await keyword. The solution was to make all calls asynchronous and await them.
cook.Init() needs an await:
private async Task Cook()
{
await cook.Init();
}
In CookchiefInit(), the CookHelperInit() call needs to be awaited:
protected async Task CookchiefInit()
{
this.Cookhelper = new Cookhelper();
Cookhelper.CookHelperInit();
}
In order to await CookHelperInit(), it needs to be made asynchronous. The startProc() call is to an async method, so it must also be awaited:
public async Task CookHelperInit()
{
this.driverWindow = new DriverWindow();
await startProc();
}

Memory leaks in .NET when doing async over sync

I have a situation where I must call an async method synchronously, and it is done so as follows:
obj.asyncMethod().Wait(myCancelToken)
If the cancellation token is switched the disposable's within the task will not get disposed despite being activated via a using statement.
The below program illustrates the problem:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace LeakTest {
class Program {
static void Main(string[] args) {
try {
var timeout = new CancellationTokenSource(TimeSpan.FromMilliseconds(100));
LongRunningTask().Wait(timeout.Token);
} catch (OperationCanceledException error) {
// handling timeout is logically okay, but expect nothing to be leaked
}
Console.WriteLine("Leaked Instances = {0}", DisposableResource.Instances);
Console.ReadKey();
}
static async Task LongRunningTask() {
using (var resource = new DisposableResource()) {
await Task.Run( () => Thread.Sleep(1000));
}
}
public class DisposableResource : IDisposable {
public static int Instances = 0;
public DisposableResource() {
Instances++;
}
public void Dispose() {
Instances--;
}
}
}
}
It seems Wait method just kills the task thread on cancellation instead of triggering an exception within that thread and letting it terminate naturally. Question is why?
You've cancelled the task returned by Wait(timeout.Token) not the one returned from LongRunningTask, if you want to cancel that one pass the token to Task.Run and also use await Task.Delay instead of Thread.Sleep and pass the token there as well.
static void Main(string[] args)
{
try
{
var timeout = new CancellationTokenSource(TimeSpan.FromMilliseconds(100));
LongRunningTask(timeout.Token).Wait();
}
catch (AggregateException error)
{
// handling timeout is logically okay, but expect nothing to be leaked
}
Console.WriteLine("Leaked Instances = {0}", DisposableResource.Instances);
Console.ReadLine();
}
static async Task LongRunningTask(CancellationToken token)
{
using (var resource = new DisposableResource())
{
await Task.Run(async () => await Task.Delay(1000, token), token);
}
}
public class DisposableResource : IDisposable
{
public static int Instances = 0;
public DisposableResource()
{
Instances++;
}
public void Dispose()
{
Instances--;
}
}
Note that the using statment will still dispose of the resource once the long running operation finishes. Run this example:
static void Main(string[] args)
{
try {
var timeout = new CancellationTokenSource(TimeSpan.FromMilliseconds(100));
LongRunningTask().Wait(timeout.Token);
} catch (OperationCanceledException error) {
// handling timeout is logically okay, but expect nothing to be leaked
}
Console.WriteLine("Leaked Instances = {0}", DisposableResource.Instances);
Console.ReadKey();
}
static async Task LongRunningTask()
{
using (var resource = new DisposableResource())
{
await Task.Run(() => Thread.Sleep(1000));
}
}
public class DisposableResource : IDisposable
{
public static int Instances = 0;
public DisposableResource()
{
Instances++;
}
public void Dispose()
{
Instances--;
Console.WriteLine("Disposed resource. Leaked Instances = {0}", Instances);
}
}
Output
Leaked Instances = 1
Disposed resource. Leaked Instances = 0
It seems Wait method just kills the task thread on cancellation instead of triggering an exception within that thread
You are incorrect, on when you cancel the only thing that happens is you stop waiting for Wait(myCancelToken) to complete, the task is still running in the background.
In order to cancel the background task you must pass the cancelation token into all of the methods down the chain. If you want the innermost layer (the long running one) to stop early that code must call token.ThrowIfCancellationRequested() throughout its code.

Running a long-running Task within a Windows Service

I have written a Windows Service project which hosts a long-running message pump task which is meant to run for the duration of the service. When the service starts, it starts the task. When the service stops, it stops the task:
void OnStart()
{
MessagePump.Start();
}
void OnStop()
{
MessagePump.Stop();
}
Where MessagePump.Start does a Task.Factory.StartNew, and MessagePump.Stop signals the task to stop and does a Wait().
So far so good, but I'm wondering how best to handle faults. If the task has an unhandled exception, I'd want the service to stop but since nothing is typically Wait-ing on the task, I imagine it'll just sit doing nothing. How can I elegantly handle this situation?
UPDATE:
The consensus seems to be using 'await' or ContinueWith. Here is how I'm currently coding my Start method to use this:
public async static void Start()
{
this.state = MessagePumpState.Running;
this.task = Task.Factory.StartNew(() => this.ProcessLoop(), TaskCreationOptions.LongRunning);
try
{
await this.task;
}
catch
{
this.state = MessagePumpState.Faulted;
throw;
}
}
Make you MessagePump.Start() method return the task. Then
MessagePump.Start().ContinueWith(t =>
{
// handle exception
},
TaskContinuationOptions.OnlyOnFaulted);
UPDATE:
I would do the next:
private MessagePump _messagePump;
async void OnStart()
{
this._messagePump = new MessagePump();
try
{
// make Start method return the task to be able to handle bubbling exception here
await _messagePump.Start();
}
catch (Exception ex)
{
// log exception
// abort service
}
}
void OnStop()
{
_messagePump.Stop();
}
public enum MessagePumpState
{
Running,
Faulted
}
public class MessagePump
{
private CancellationTokenSource _cancallationTokenSrc;
private MessagePumpState _state;
public async Task Start()
{
if (_cancallationTokenSrc != null)
{
throw new InvalidOperationException("Task is already running!");
}
this._state = MessagePumpState.Running;
_cancallationTokenSrc = new CancellationTokenSource();
var task = Task.Factory.StartNew(() => this.ProcessLoop(_cancallationTokenSrc.Token), _cancallationTokenSrc.Token);
try
{
await task;
}
catch
{
this._state = MessagePumpState.Faulted;
throw;
}
}
public void Stop()
{
if (_cancallationTokenSrc != null)
{
_cancallationTokenSrc.Cancel();
_cancallationTokenSrc = null;
}
}
public void ProcessLoop(CancellationToken token)
{
// check if task has been canceled
while (!token.IsCancellationRequested)
{
Console.WriteLine(DateTime.Now);
Thread.Sleep(1000);
}
}
}
You can try something like this :
void OnStart()
{
MessagePump.StartAsync();
MessagePump.ErrorEvent += OnError();
}
Then your StartAsync will look something like:
public async Task StartAsync()
{
// your process
// if error, send event to messagePump
}
And if you decide to use Tasks, then it is better to use Task.Run and not Task.Factory.StartNew()

ManualResetEvent inconsistent behaviour with regards to unblocking

The current problem I'm facing is the fact that occasionally, a waiting thread does not proceed although the ManualResetEvent is Set.
So in ClassA I've got the following code snippet:
private ManualResetEvent readyEvent = new ManualResetEvent(false);
public async Task Run(CancellationToken cancellationToken)
{
try
{
await RunAt(...);
readyEvent.Reset();
}
catch (Exception e)
{
var onRequiresRestartEvent = RequiresRestartEvent;
if (onRequiresRestartEvent != null)
{
ThreadPool.QueueUserWorkItem(obj=>onRequiresRestartEvent(this,
EventArgs.Empty));
}
}
}
private IEnumerable<string> ListStuff(Match match)
{
// Do some stuff
readyEvent.Set();
}
In ClassB, I've got a method:
public override void WaitUntilReady(int timeoutMilliseconds)
{
if (!classA.ReadyEvent.WaitOne(timeoutMilliseconds)) // wait
{
throw new TimeoutException("Timeout waiting for the modem");
}
classA.ReadyEvent.Reset();
}
I've put a breakpoint on ClassA.ListStuff and readyEvent.Set() is indeed executed but for some reason, program execution doesn't get past the .WaitOne in ClassB.
Is there anything obviously wrong with this code? If not, what steps could I take to debug this issue?

Categories