The following code seems as though it should swallow any type of exception in the try block, but the IIS worker process periodically dies and restarts because of an unhandled exception (marked with a comment.)
try
{
while (true)
{
DispatcherTask task = null;
lock (sync)
{
task = this.getTask();
if (task == null)
{
Monitor.Wait(sync);
continue;
}
}
lock (task)
{
task.Result = task.Task.DynamicInvoke(task.Params);
// ^ Delegate.DynamicInvoke(object[]) throws a TargetInvocationException
Monitor.PulseAll(task);
}
}
}
catch (Exception e)
{
}
UPDATE:
Definition of DispatcherTask:
private class DispatcherTask
{
public Delegate Task;
public object[] Params;
public object Result;
}
You cannot catch the exceptions of another thread, at least not in this way. Catch your exception inside the newly opened thread and you will be fine.
In .NET 4 and up, AccessViolationException will bypass catch blocks by default. Catching of such exceptions can be enabled in web.config, but should not be, as they typically result from errors in unmanaged code and signal that the application state is corrupted.
Related
I try to start some action in background, I am not interested in its result, but in case of an error I'd like to log it, and - of course - prevent the application (here: a Windows service) from crashing.
public static void CreateAndStartTaskWithErrorLogging(Action _action, string _componentName, string _originalStacktrace = null)
{
DateTime started = HighPrecisionClock.Now;
Task task = new Task(_action);
task.ContinueWith(_continuation => _continuation.LogExceptions(_componentName, started, _originalStacktrace));
task.ConfigureAwait(false);
task.Start();
}
internal static void LogExceptions(this Task _t, string _componentName, DateTime _started, string _originalStacktrace = null)
{
try
{
_t.Wait(1000);
}
catch (Exception ex)
{
Logger.LogError(_componentName, $"An exception occurred in a fire-and-forget task which was started at {_started}.\r\n" +
$"The original stack trace is:\r\n{_originalStacktrace}");
Logger.LogException(_componentName, ex);
}
try
{
_t.Dispose();
}
catch (Exception dex)
{
Logger.LogException(_componentName, dex);
}
}
Without ConfigureAwait(false) and without _t.Dispose(), the catch works and logs the exception. But the application crashes several seconds later (i.e. on the Finalizer thread?). The entry in the Microsoft Event Viewer shows that exception.
With ConfigureAwait and _t.Dispose(), I do not see the exception in the logs, the application just crashes.
What's wrong with the idea shown above?
Edit:
Meanwhile I tested without ConfigureAwait but with _t.Dispose. I could catch about 10 such exceptions, and none made the application crash. That seems to solve the issue, but I do not understand the reason for that, so the situation is still bad.
What does ConfigureAwait(false) do to Exceptions in the task (or in tasks started within that task, e.g. by a Parallel.ForEach further down)?
Why does the Dispose - which is called on the continuation, not the task proper according to a comment - prevent the crash (the Finalizer does not call Dispose, but Dispose may set some flags influencing its behavior)?
Edit 2:
Also that does not work all the time, only most of the time. Suggested solution 1 below also fails sometimes.
In the crashing context, the function is called with Utilities.TaskExtensions.CreateAndStartTaskWithErrorLogging(() => DataStore.StoreSyncedData(data), Name);, where DataStore is set to a composite which in turn calls Parallel.ForEach(m_InnerDataStores, _store => { _store.StoreSyncedData(_syncedData); }); on its members. One of them writes a video with the Accord library, which sometimes causes an AccessViolation at <Module>.avcodec_encode_video2(libffmpeg.AVCodecContext*, libffmpeg.AVPacket*, libffmpeg.AVFrame*, Int32*), i.e. the exception may come from non-managed code.
Of course, I could try to catch it somewhere down there - but that's not the objective of this method. I expect it to be able to safely run any code in the background without crashing the application.
This is my suggestion for logging errors:
public static void OnExceptionLogError(this Task task, string message)
{
task.ContinueWith(t =>
{
// Log t.Exception
}, TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously);
}
Usage example:
var task = Task.Run(action);
task.OnExceptionLogError("Oops!");
try
{
await task;
}
catch
{
// No need to log exception here
}
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 new to tasks and I hope you can help me out with this.
Here is code:
Task tast = null;
try
{
tast = new Task(() =>
{
...
});
tast.Start();
if (tast != null)
{
tast.Wait();
if (tast.Exception != null)
{
// catch exception here
}
}
}
catch (Exception err)
{
// not here?
}
The exception is being caught inside catch statement but not inside task.Exception != null.
Why is this happening? Task should be on own thread.
I would rather like to make the task know about exception and then ask if exception != null.
How can I make that work?
I am sorry in case this is a duplicate. Just let me know in comments and I will remove this question.
You're calling Task.Wait() - which will throw an exception if the task is faulted. If you don't call Task.Wait(), you won't get the exception in your thread... but of course you won't spot when it's finished, either. There are various ways you could wait until it's finished (such as attaching a continuation task and waiting until that completes) but the simplest approach is just to call Task.Wait() with a catch block:
try
{
task.Wait();
}
catch (AggregateException)
{
// We'll handle this later.
}
Whenever a thread in my ThreadPool throws an exception, my code seems to be stuck at the catch block inside the thread function. How do I get the exception back to the main thread?
The best practice is that your background threads should not throw exceptions. Let them handle their exceptions on their own.
Ideally you should wrap the code in your method that executes on a thread in a try-catch block and handle the exception in the catch block. Do not re-throw it from the catch block.
Read this for more details. http://www.albahari.com/threading/#_Exception_Handling
If you want to update the UI from background thread you can do that by using Control.InvokeRequired property and Control.Invoke method. See the MSDN links for details and examples.
It's not possible to transfer exception from a thread to another one. What can you do is to built some synchronization mechanism to transfer exception information between threads and then throw a new exception from the target thread something like:
class Program
{
Exception _savedException = null;
AutoResetEvent _exceptionEvent = new AutoResetEvent(false);
static void Main(string[] args)
{
Program program = new Program();
program.RunMain();
}
void RunMain()
{
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadMethod));
while (true)
{
_exceptionEvent.WaitOne();
if (_savedException != null)
{
throw _savedException;
}
}
}
void ThreadMethod(object contxt)
{
try
{
// do something that can throw an exception
}
catch (Exception ex)
{
_savedException = ex;
_exceptionEvent.Set();
}
}
}
If you have a Win form application things are much simpler. In the catch clause of your thread use Invoke (or BeginInvoke) method of your form, providing it with the exception details. In the method launched with Invoke you can rethrow or treat your exception as you want.