I have an application that are executing 4 different jobs parallel. I use the parallel task library.
The code looks like this:
while (true)
{
var fetch = new FetcherHandler();
var tasks = new Task[4];
tasks[0] = Task.Factory.StartNew(fetch.GetJobs);
tasks[1] = Task.Factory.StartNew(fetch.GetStatusNew);
tasks[2] = Task.Factory.StartNew(fetch.GetJobsForStatus);
tasks[3] = Task.Factory.StartNew(fetch.GetStatusOld);
Task.WaitAll(tasks);
Thread.Sleep(10000);
}
The thread.Sleep above will never be reached since all these 4 tasks is in a never ending loop. Code example for the first task:
public void GetJobs()
{
while (true)
{
try
{
handler.GetNewJob();
}
catch (Exception exception)
{
var mail = new MailService();
mail.SendExeption("Error has accured in GetJobs", exception);
throw;
}
}
}
Thread.Sleep(15000); }}
The above code works great, it does some jobs and then it sleeps for 15 sec, and then it does it again. The problem occurres when I get an exception.
The exception is caught alright, and sends me an mail, but the thred doesn't continue in the loop after the exception, so the GetNewJob() method will never get executed again.
Any ideas what happens to the thread when exception hits, and how I can "save" the thread so it can continue?
Becasue you throw an exception, so the exception propagates on top of the stack and break execution of the source thread.
catch (Exception exception)
{
var mail = new MailService();
mail.SendExeption("Error has accured in GetJobs", exception);
throw; //THIS LINE !
}
You can use an event to raise it, say, ExceptionCaught(..) and listen for that event inside your program.
Just remove the throw; at the end of your catch clause.
From MSDN:
A throw statement can be used in a catch block to re-throw the
exception that is caught by the catch statement.
So you're rethrowing the caught exception which causes the thread to interrupt, never executing again...
More information: What happens when a .NET thread throws an exception?
Related
Problem
Several tasks are run in parallel, and all, none, or any of them might throw exceptions. When all the tasks have finalized, all the exceptions that might have happened must be reported (via log, email, console output.... whatever).
Expected behavior
I can build all the tasks via linq with async lambdas, and then await for them running in parallel with Task.WhenAll(tasks). Then I can catch an AggregateException and report each of the individual inner exceptions.
Actual behavior
An AggregateException is thrown, but it contains just one inner exception, whatever number of individual exceptions have been thrown.
Minimal complete verifiable example
static void Main(string[] args)
{
try
{
ThrowSeveralExceptionsAsync(5).Wait();
}
catch (AggregateException ex)
{
ex.Handle(innerEx =>
{
Console.WriteLine($"\"{innerEx.Message}\" was thrown");
return true;
});
}
Console.ReadLine();
}
private static async Task ThrowSeveralExceptionsAsync(int nExceptions)
{
var tasks = Enumerable.Range(0, nExceptions)
.Select(async n =>
{
await ThrowAsync(new Exception($"Exception #{n}"));
});
await Task.WhenAll(tasks);
}
private static async Task ThrowAsync(Exception ex)
{
await Task.Run(() => {
Console.WriteLine($"I am going to throw \"{ex.Message}\"");
throw ex;
});
}
Output
Note that the output order of the "I am going to throw" messages might change, due to race conditions.
I am going to throw "Exception #0"
I am going to throw "Exception #1"
I am going to throw "Exception #2"
I am going to throw "Exception #3"
I am going to throw "Exception #4"
"Exception #0" was thrown
That's because await "unwraps" aggregate exceptions and always throws just first exception (as described in documentation of await), even when you await Task.WhenAll which obviously can result in multiple errors. You can access aggregate exception for example like this:
var whenAll = Task.WhenAll(tasks);
try {
await whenAll;
}
catch {
// this is `AggregateException`
throw whenAll.Exception;
}
Or you can just loop over tasks and check status and exception of each.
Note that after that fix you need to do one more thing:
try {
ThrowSeveralExceptionsAsync(5).Wait();
}
catch (AggregateException ex) {
// flatten, unwrapping all inner aggregate exceptions
ex.Flatten().Handle(innerEx => {
Console.WriteLine($"\"{innerEx.Message}\" was thrown");
return true;
});
}
Because task returned by ThrowSeveralExceptionsAsync contains AggregateException we thrown, wrapped inside another AggregateException.
I am following this MSDN guide to handle the exceptions within a Task.
This is what I wrote:
var myTask = Task.Run(() =>
{
throw new Exception("test");
});
try
{
myTask.Wait();
}
catch (Exception e)
{
return false;
}
I have set a breakpoint within the catch block, but at debug runtime, the code does not reach the breakpoint, and it's giving me:
Exception is unhandled by user code
I have no idea what is going on as I have followed very closely to the example from the MSDN guide. In fact, I copied the example to my project and it's still giving the same problem.
Is there any method I can handle the exception outside the Task? I need to return a boolean value based on the fact if the task throws any Exception or not.
Edit
To make it clearer for some of you, this is a more complete set of codes:
public bool ConnectToService()
{
try
{
// Codes for ServiceHost etc etc, which I'm skipping
// These codes are already commented out for this test, so they do nothing
var myTask = Task.Run(() =>
{
// Supposed to connect to a WCF service, but just throwing a test exception now to simulate what happens when the service is not running
throw new Exception("test");
});
try
{
myTask.Wait();
}
catch (Exception e)
{
return false;
}
return true;
}
catch (Exception)
{
return false;
}
}
Caller:
public void DoSomething()
{
try
{
// Other irrelevant stuff
if (ConnectToService())
{
DoAnotherThing();
}
}
catch (Exception)
{
}
}
I would also want to point out I have a solution for this, but it's puzzling why an example from MSDN isn't working for me. I would think that my own solution is not elegant, so I'm still looking for a more elegant solution.
Exception taskException = null;
var myTask = Task.Run(() =>
{
try
{
throw new Exception("test");
}
catch (Exception e)
{
taskException = e;
}
});
try
{
myTask.Wait();
if (taskException != null) throw taskException;
}
catch (Exception e)
{
return false;
}
When a task is run, any exceptions that it throws are retained and re-thrown when something waits for the task's result or for the task to complete
task.Wait() Rethrows any exceptions
task.Result Rethrows any exceptions
As well, your code works correctly
Just press f5 while catching an exception and you will see that will get your point
According to MSDN Task.Run:
Queues the specified work to run on the thread pool and returns a Task object that represents that work.
So You throwing your exception on different thread than you trying to catch it. You should deal with exception on same thread.
Alternatively you can deal with unhandled exceptions in global AppDomain.UnhandledException event.
Jai, as mentioned, this code will always work. I think you will have to enable some settings in visual studio. The setting is turned off and because of this, you are getting "Exception not handled by user code".
try checking Under Tools, Options, Debugging, General, Enable just my code.
Also, you can use something like below if you don't like to bother about try/catch stuff :
myTask.ContinueWith(<you can access Exception property here to see if there was an exception>)
I had the same Problem and solved with ContinueWith
See:
var task = Task.Run(() =>
{
ChatHubWrapper chatHub = Ordem_ServicoBLL.sendMensagemIniciarChatPelaVr(pessoaWrapper.OrdemServico);
foreach (var mensagem in chatHub.MensagensEnviadas)
ChatHub.sendMensagemTodaSala(pessoaWrapper.OrdemServico.ID, mensagem);
})
.ContinueWith((t) =>
{
if (t.IsFaulted)
setPanelErrorWhats(t.Exception.InnerException.Message); // or throw new Exception...
});
task.Wait();
if (task.IsCompleted)
Response.Redirect(pessoaWrapper.OrdemServico.getUrlViewOSSuporte());
With this you Don't need a create Exception taskException = null;
And is not good to use catch Inside Task.Run
#Jai, please try to move a Task.Run to the inside of try/catch block. I think Task.Run executes imediatelly so you may get exception because of that.
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
}));
}
I am in a strange situation, I am using task and continue with upon faulted i am calling one method to process upon faulted or success but the function does not get fired.
Below is my code but upon expcetion it does not executes the UdpateResult method, what I am missing here.
var task = new Task.Factory.StartNew(SomeMethod());
task.ContinueWith(
t1 => Handler.UpdateResult(t1.Result, t1.Exception),
TaskContinuationOptions.ExecuteSynchronously);
try
{
task.Wait();
}
catch (AggregateException exception)
{
foreach (var innerException in exception.Flatten().InnerExceptions)
{
if (innerException is InvalidOperationException)
{
throw innerException;
}
throw new InvalidOperationException(string.Empty, innerException);
}
}
You're trying to use t1.Result within your continuation. If t1 has faulted, then accessing t1.Result will itself throw an exception.
You either need a single continuation which can handle any kind of end result, or you should attach different continuations for success and failure cases.
I have the following code
Task load = Task.Factory.StartNew(() =>
{
Threading.Thread.Sleep(5000);
throw new Exception("bad error");
});
try{
load.Wait();
}catch(AggregateException aex){
MessageBox.Show("Error Caught!");
}
Here as you can see, I create a task and throw an exception.
The exception is then caught on the UI thread. But with this this set up, the UI will be un responsive.
What is the work around for this to make the UI responsive and catch the Exception?
There is a couple of ways to handle this.
You could use ContinueWith and check there, or you could just hook into the global task exception handler TaskScheduler.UnobservedTaskException). (details to come)
ContinueWith for exception handling only:
load.ContinueWith(previousTask =>
{
//exception message here
}, TaskContinuationOptions.OnlyOnFaulted);
or for with a normal try catch:
load.ContinueWith(previousTask =>
{
try
{
previousTask.Result
}
catch(Exception ex){//message here}
});
You'll want to add a continuation to the task, rather than using Wait or any other means of blocking on the task.
load.ContinueWith(t => MessageBox.Show(t.Exception.Message)
, TaskContinuationOptions.OnlyOnFaulted);