Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Async code without waiting for completion

I'm currently having issues with IIS crashing out leaving the following messages in the event log. They're not too helpful in directing me to the actual source of the error but a bit of research suggests this is just a case of spawning tasks but not waiting for the result, when they do eventually complete if the parent process has completed it cannot be associated with the parent thread which causes a null reference exception. Is that correct?

For the most part I have removed or added awaits where this was going on but there are some areas where it is handy. One such example is on session start is memory caching a few details unique to the session, however they're not vital immediately so I spin up a task to do this work but don't await it.

I have added ConfigureAwait(false), is this sufficient to prevent the error in future? It sounds like this will remove the thread switching which I assume will prevent the error.

Task.Run(() =>
{
    // Do caching here

}).ConfigureAwait(false);

ASP.NET 4.0.30319.0

Exception: System.NullReferenceException

Message: Object reference not set to an instance of an object.

StackTrace:    at System.Web.ThreadContext.AssociateWithCurrentThread(Boolean setImpersonationContext)
   at System.Web.HttpApplication.OnThreadEnterPrivate(Boolean setImpersonationContext)
   at System.Web.LegacyAspNetSynchronizationContext.CallCallbackPossiblyUnderLock(SendOrPostCallback callback, Object state)
   at System.Web.LegacyAspNetSynchronizationContext.CallCallback(SendOrPostCallback callback, Object state)
   at System.Threading.Tasks.AwaitTaskContinuation.RunCallback(ContextCallback callback, Object state, Task& currentTask)
--- End of stack trace from previous location where exception was thrown ---
   at System.Threading.Tasks.AwaitTaskContinuation.<ThrowAsyncIfNecessary>b__1(Object s)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
   at System.Threading.ThreadPoolWorkQueue.Dispatch()

.NET Runtime

Application: w3wp.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.NullReferenceException
Stack:
   at System.Threading.Tasks.AwaitTaskContinuation.<ThrowAsyncIfNecessary>b__1(System.Object)
   at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
   at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
   at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
   at System.Threading.ThreadPoolWorkQueue.Dispatch()

Application Error

Faulting application name: w3wp.exe, version: 7.5.7601.17514, time stamp: 0x4ce7afa2
Faulting module name: KERNELBASE.dll, version: 6.1.7601.18015, time stamp: 0x50b8479b
Exception code: 0xe0434352
Fault offset: 0x0000000000009e5d
Faulting process id: 0x1d98
Faulting application start time: 0x01ceaf8ea10ece66
Faulting application path: c:\windows\system32\inetsrv\w3wp.exe
Faulting module path: C:\Windows\system32\KERNELBASE.dll
Report Id: 341b9a76-1b82-11e3-8e17-005056be0005
like image 979
Hawxby Avatar asked Sep 12 '13 09:09

Hawxby


1 Answers

After a morning of chasing this problem around I eventually discovered there was a path which could allow for the parent to bypass the await creating this problem. A quick refactoring to prevent this solved the problem.

In its most simple form the code causing the problem was along the lines of this:

var getDataTask = getData();

if(some_condition == true) {
    return some_object;
}

getDataTask.Wait();

return getDataTask.result;

If some_condition == true the method would return without waiting for getDataTask to complete. Refactoring to stop that fixed it.

like image 191
Hawxby Avatar answered Sep 18 '22 15:09

Hawxby