Task Factory Method with Delay - c#

I'm trying to call a particular method with 5 mins delay:
try
{
HttpContext ctx = HttpContext.Current;
System.Threading.Tasks.Task.Factory.StartNew(() =>
{
HttpContext.Current = ctx;
System.Threading.Thread.Sleep(5 * 60 * 1000);
Sendafter5mins(param1,params2);
});
}
catch (Exception EX)
{
//Log Exception if any
}
This method is failing silently sometimes without any exception in log.
Please Suggest me is this the right way to fire a method with 5 mins delay.

Since you don't await the Task, nor Wait() on it, any exception thrown from Sendafter5mins(..) will not get caught in your catch block. If you are not using .NET 4.5, this should fail the whole process since the exception will fail the finalizer thread. Change your code to:
try
{
HttpContext ctx = HttpContext.Current;
System.Threading.Tasks.Task.Factory.StartNew(() =>
{
try
{
HttpContext.Current = ctx;
System.Threading.Thread.Sleep(5 * 60 * 1000);
Sendafter5mins(param1,params2);
}
catch(Exception e)
{
//Log Exception if any
}
});
}
catch (Exception EX)
{
//This will catch unlikely exceptions thrown from HttpContext ctx = HttpContext.Current
// or the creation of the Task
}

If by "failing silently" you mean there's an exception and you don't catch it that's because you are starting a new task without waiting for the result. Your try-catch can't catch the exception as it's stored inside the task and isn't rethrown.
Anyways, if all you want is a delay use Task.Delay with async-await instead of creating a new Task and blocking its thread:
async Task SendAfterDelay()
{
try
{
await Task.Delay(TimeSpan.FromMinutes(5));
Sendafter5mins(param1,params2);
}
catch (Exception e)
{
// handle exception
}
}

Related

Imitation of OperationCanceledException scenario with unit-test fails

I use Moq 4.18.2 framework for my tests.
The RtspClient might throw an OperationCanceledException from ConnectAsync. So, I try to test this scenario. My test below throws an exception System.OperationCanceledException: The operation was canceled. and the catch (OperationCanceledException) never gets executed. What am I doing wrong here?
RTSP
public interface IRtspClient : IDisposable
{
event EventHandler<RawFrame> FrameReceived;
Task ConnectAsync(CancellationToken token);
Task ReceiveAsync(CancellationToken token);
}
Method that uses IRtspClient
public async Task ConnectAsync(CancellationToken token = default)
{
try
{
await _rtspClient.ConnectAsync(token).ConfigureAwait(false);
OnConnected();
}
catch (OperationCanceledException ex)
{
OnConnectAttemptCanceled(ex);
throw;
}
catch(Exception ex)
{
OnFailedToConnect(ex);
throw;
}
}
Test
[TestMethod]
public async Task ConnectAsync_Canceled()
{
var expectedCanceledTaskStatus = true;
var tcs = new CancellationTokenSource();
tcs.Cancel();
var rtspClient = new Mock<IRtspClient>();
rtspClient
.Setup(_ => _.ConnectAsync(It.IsAny<CancellationToken>()))
.Returns(Task.FromException<OperationCanceledException>(new OperationCanceledException()))
var actualCanceledTaskStatus = false;
var camera = new MyCamera(rtspClient.Object);
camera.FailedToConnect += () => actualCanceledTaskStatus = true;
await camera.ConnectAsync(tcs.Token);
Assert.AreEqual(expectedCanceledTaskStatus, actualCanceledTaskStatus);
}
UPDATE
Added missing await as suggested by #Dai, but my test still fails. Can anyone take a look at the test code?
You need to await the returned Task inside the try{} block - otherwise
synchronous control will immediately leave the try{} block.
Exceptions thrown inside an anonymous function (or local function, or lambda method, or ye olde school delegate() local) will not be caught by the catch.
Also, CancellationTokenSource is IDisposable, so you should change your ConnectAsync_Canceled test to wrap it in a using() block.
Also, don't swallow exceptions - so my code below captures both exceptions for possible investigation and re-throws them with throw; (don't use throw ex;: it resets the recorded stack-trace; instead just do throw; by itself).
With OperationCanceledException and/or TaskCanceledException specifically, the exception needs to be re-thrown right back to the original caller (i.e. the owner of the CancellationTokenSource); whereas if a TaskCanceledException is caught and handled without the corresponding Task "seeing" then the caller will assume the operation succeeded despite the cancelation request.
Change your code to this:
public async Task ConnectAsync( CancellationToken cancellationToken = default )
{
try
{
await this.rtspClient.ConnectAsync(cancellationToken ).ConfigureAwait(false);
this.OnConnected();
}
catch( OperationCanceledException cEx )
{
this.OnConnectAttemptCanceled( cEx );
throw; // Re-throw so the `Task` representing *this method* (`ConnectAsync`) will report as Cancelled rather than Succeeded.
}
catch( Exception ex )
{
this.OnFailedToConnect( ex );
throw; // Re-throw so the `Task` representing *this method* (`ConnectAsync`) will report as Failed rather than Succeeded.
}
}
I found my mistake (in addition to what #Dai noticed). I should have either put await camera.ConnectAsync from my test in try-catch or used Assert.ThrowsExceptionAsync. I chose the latter. Here is the working test:
[TestMethod]
public async Task ConnectAsync_Canceled()
{
var expectedTaskCanceledStatus = true;
var rtspClient = new Mock<IRtspClient>();
rtspClient
.Setup(_ => _.ConnectAsync(default(CancellationToken)))
.Returns(Task.FromException(new OperationCanceledException()));
var actualTaskCanceledStatus = false;
var camera = new MyCamera(rtspClient.Object);
camera.ConnectAttemptCanceled += () => actualTaskCanceledStatus = true;
await Assert.ThrowsExceptionAsync<OperationCanceledException>(async () => await camera.ConnectAsync());
Assert.AreEqual(expectedTaskCanceledStatus, actualTaskCanceledStatus);
}

Converting sync to async code got unhandled System.OperationCanceledException: 'The operation was canceled.'

I'm trying to convert my sync functions to async. In all my sync functions I have a cancellation token which is used on function, task and parallel blocks. I have a try/catch block before calling the async function, but I'm getting an unhandled exception:
Exception thrown: 'System.OperationCanceledException' in
System.Threading.Tasks.Parallel.dll An exception of type
'System.OperationCanceledException' occurred in
System.Threading.Tasks.Parallel.dll but was not handled in user code
The operation was canceled.
My async function:
public async Task DecodeAsync(string? fileFullPath, FileDecodeType fileDecodeType, OperationProgress? progress = null) =>
await Task.Run(() => Decode(fileFullPath, fileDecodeType, progress), progress?.Token ?? default);
How I call it:
try
{
await SlicerFile.DecodeAsync(fileName, fileDecodeType, Progress);
}
catch (OperationCanceledException) { } // Do not work!
catch (Exception exception) // Works for other exceptions
{
await this.MessageBoxError(exception.ToString(), "Error opening the file");
}
catch (OperationCanceledException) is never reached nor catch (Exception exception) in a cancel event. As my try is at top most, why doesn't it catch the exception?
But if I do:
public async Task DecodeAsync(string? fileFullPath, FileDecodeType fileDecodeType, OperationProgress? progress = null) =>
await Task.Run(() => throw new Exception("Test"));
I get the exception catch on the generic Exception (it's handled)
In other hand with old code it's working and handling the OperationCanceledException:
var task = await Task.Factory.StartNew( () =>
{
try
{
SlicerFile.Decode(fileName, fileDecodeType, Progress);
return true;
}
catch (OperationCanceledException) {} // Works!
catch (Exception exception)
{
Dispatcher.UIThread.InvokeAsync(async () =>
await this.MessageBoxError(exception.ToString(), "Error opening the file"));
}
return false;
});
What am I doing wrong?
The results of Task.Run don't need to be awaited right there necessarily. You can just return the running Task and then the method doesn't need to be awaited or be async any longer.
Task DecodeAsync(string? fileFullPath, FileDecodeType fileDecodeType, OperationProgress? progress = null) => Task.Run(() =>
Decode(fileFullPath, fileDecodeType, progress), progress?.Token ?? default);
And since you're passing in progress with a token, you can monitor that to exit the decode method cleanly instead of trying to catch and ignore the operation cancelled exception.
You'll have better luck if you make the decode method itself asynchronous if you can. It already returns a Task, so it could return a Task (or whatever). Your old code is also asynchronous in the same way, so there's no advantage to your new code that I can see.

Task swallows the exception thrown

In the method below, when an exception is thrown in the TRY block, it is being swallowed. How can I make it throw the exception so that it gets written to log in the catch block? The log writer works fine. Thanks!
public static bool MonitorQueueEmptyTask(string queueName, CancellationTokenSource tokenSource)
{
try
{
Task<bool> task = Task.Factory.StartNew<bool>(() =>
{
while (!QueueManager.IsQueueEmpty(queueName))
{
if (tokenSource.IsCancellationRequested)
{
break;
}
Thread.Sleep(5000);
throw new Exception("Throwing an error!"); //THIS THROW IS SWALLOWED -- NO LOG WRITTEN ON CATCH
};
return true;
}, tokenSource.Token);
}
catch (Exception ex)
{
WriteExceptionToLog(ex.Stack); //it's not that this method doesn't work. it works fine.
return false;
}
return true;
}
If you want to fire and forget, you can attach a continuation using ContinueWith. The current try-catch will not help you at all, as the exception is encapsulated inside the Task. If this is "fire and forget", than you can log the exception:
public static Task MonitorQueueEmptyTask(
string queueName, CancellationTokenSource tokenSource)
{
return Task.Factory.StartNew<bool>(() =>
{
while (!QueueManager.IsQueueEmpty(queueName))
{
if (tokenSource.IsCancellationRequested)
{
break;
}
Thread.Sleep(5000);
throw new Exception("Throwing an error!");
};
}, tokenSource.Token, TaskCreationOptions.LongRunning).ContinueWith(faultedTask =>
{
WriteExceptionToLog(faultedTask.Exception);
}, TaskContinuationOptions.OnlyOnFaulted);
}
This, in turn, will not propagate the exception after it's thrown, but will provide a mechanism to log the error. If you want the exception to be properly handled, you can register to TaskScheduler.UnobservedTaskException. Additionally, you can set ThrowUnobservedTaskExceptions enabled="true" in your configuration if you want unhandled exceptions to terminate your application. ContinueWith will consider the exception "handled" once you look at the task.Exception property.
The exception is not swallowed; it's just that it doesn't occur on the thread that executes the try/catch block, but on the separate Task thread.
If you don't observe the task's result or exception, when the task is eventually garbage collected, it will throw an exception saying that the task was not observed. Unless you catch that by handling the TaskScheduler.UnobservedTaskException, it will crash the process.
I also had a problem with this, and i really dislike the whole idea of App.config, so can provide another solution to prevent the exceptions disappearing :)
Save the exception then throw it after the Task.Run has completed, e.g.
private async void Function() {
Exception save_exception = null;
await Task.Run(() => {
try {
// Do Stuff
} catch (Exception ex) {
save_exception = ex;
}
}).ContinueWith(new Action<Task>(task => {
if (save_exception != null)
throw save_exception;
// Do Stuff
}));
}

After an exception, keep on running

For example:
try
{
Task1();
Task2();
Task3();
}
catch (Exception ex)
{
}
Right now if an exception occurs in Task1(), the code in Task2 and Task2 method does not run. The program stops.
How could I make it so when an exception occurs, the code / methods that below it would keep on running to the end.
Thanks
An exception moves execution to the end of the try block and into the catch block. To do what you want, you'd have to use separate try/catch blocks:
try
{
Task1();
}
catch (Exception ex)
{
}
try
{
Task2();
}
catch (Exception ex)
{
}
try
{
Task3();
}
catch (Exception ex)
{
}
You could put your tasks in a collection (provided they all have the same signature) and loop, but the net effect would be the same:
var tasks = new Action[] {Task1, Task2, Task3};
foreach(var task in tasks)
{
try
{
task();
}
catch (Exception ex)
{
}
}
Currently, in the code that you have, if there is an exception throw trying to start Task1() then the other two tasks are not started. If that task is started without error but results in a task that is in a Faulted state, then your other tasks are properly started.
Generally one would not expect methods like these to throw an exception starting the task in most situations. Null checking arguments is something commonly done, but other than that one would generally expect such methods to not fail to start the task. If you have any control over the method, consider re-designing it so that it generates a faulted task instead of throwing an exception, unless you have a good reason to do otherwise.
You may also want to create a method that takes a task-returning method and, if it fails to generate a task, instead creates a faulted task. If it is successful, it can just return that task:
public static Task WrapExceptions(this Func<Task> function)
{
try
{
return function();
}
catch (Exception e)
{
var tcs = new TaskCompletionSource<bool>();
tcs.SetException(e);
return tcs.Task;
}
}
If you want to ensure all tasks are started even if there is an exception when starting the task, then you need to wrap each method call in its own try/catch.
Put each statement in its own try-catch block:
try
{
Task1();
}
catch (Exception ex)
{
}
try {
Task2();
}
catch (Exception ex)
{
}
try {
Task3();
}
catch (Exception ex)
{
}

Catching Error when using Task.Factory

i am using the following
Task.Factory.StartNew(() => DoPrintConfigPage(serial));
then the function i am calling looks like this
private void DoPrintConfigPage(string serial)
{
//do printing work
}
My problem is an exception is being thrown inside the thread and not being handled.
I have tried wrapping it in a try catch
try
{
Task.Factory.StartNew(() => DoPrintConfigPage(serial));
}
catch (Exception ex) { }
but it still is not catching the error and thus crashing the application.
How can I catch exceptions in the main thread so I can handle them?
Update
I have made the changes recommended below and still it is saying the exception is unhandled
var task = Task.Factory.StartNew(() => DoPrintConfigPage(serial))
.ContinueWith(tsk =>
{
MessageBox.Show("something broke");
},TaskContinuationOptions.OnlyOnFaulted);
then in my DoConfigPage I added another try catch.
In this catch is now where it is crashing and saying the exception being thrown was unhandled, what am I missing?
private void DoPrintConfigPage(string serial)
{
try
{
//call the print function
}
catch (Exception ex)
{
throw ex; //it is crashing here and saying it is unhandled
}
}
I also tried what Eric J. suggested with the same results
var task = Task.Factory.StartNew(() => DoPrintConfigPage(serial));
try
{
task.Wait();
}
catch (AggregateException ex) { MessageBox.Show("something broke"); }
Alternatively, you can chain your task creation and add a ContinueWith:
var job = Task.Factory
.StartNew(...)
.ContinueWith(tsk =>
{
// check tsk for exception and handle
});
EDIT: This snippet, when run, pops up the message box for me:
void Main()
{
var serial = "some serial";
var task = Task.Factory
.StartNew(() => DoPrintConfigPage(serial))
.ContinueWith(tsk =>
{
MessageBox.Show("something broke");
var flattened = tsk.Exception.Flatten();
// NOTE: Don't actually handle exceptions this way, m'kay?
flattened.Handle(ex => { MessageBox.Show("Error:" + ex.Message); return true;});
},TaskContinuationOptions.OnlyOnFaulted);
}
public void DoPrintConfigPage(string serial)
{
throw new Exception("BOOM!");
}
Your try block is exited right after you start the new task, because that method just continues to run.
Instead you can catch the Exception as an AggregateException where you wait for the task (or multiple tasks) to complete:
var task1 = Task.Factory.StartNew(() =>
{
throw new MyCustomException("I'm bad, but not too bad!");
});
try
{
task1.Wait();
}
catch (AggregateException ae)
{
// Assume we know what's going on with this particular exception.
// Rethrow anything else. AggregateException.Handle provides
// another way to express this. See later example.
foreach (var e in ae.InnerExceptions)
{
if (e is MyCustomException)
{
Console.WriteLine(e.Message);
}
else
{
throw;
}
}
}
http://msdn.microsoft.com/en-us/library/dd997415.aspx
If you are not waiting on your task, I think the easiest solution is found in Task.Exception:
Gets the AggregateException that caused the Task to end prematurely.
If the Task completed successfully or has not yet thrown any
exceptions, this will return null.
I am using something like this:
Task.Factory.StartNew(() => DoStuffHere())
.ContinueWith(task =>
{
if (task.Exception != null)
Log("log all the exceptions!");
});
You should also know about
System.Threading.Tasks.TaskScheduler.UnobservedTaskException.
If you are in the business of creating "fire and forget" Task instances, you'll want to subscribe to that event at the start of your program.
Maybe you are trying to catch a Corrupted State Exception. Since .NET 4 applications are unable to catch such exceptions by default. You could try to add the legacyCorruptedState­­ExceptionsPolicy=true entry to your configuration file as stated in the MSDN article linked above.

Categories