首页 新闻 会员 周边 捐助

async方法异常,导致w3wp进程崩溃

0
悬赏园豆:50 [已解决问题] 解决于 2014-06-20 14:33

问题描述:

业务上需要在执行一个操作(需lock)之后异步发送短信通知,大致代码如下:

lock (_locker)
{
    //其他逻辑

    //异步发送短信,不等待
    MessageManager.SendMessageAsync(numbers, message);   
}

其中,SendMessageAsync是一个静态方法,大致如下:

public static async Task<bool> SendMessageAsync(IEnumerable<string> numbers, string content)
{
    return await Task.Factory.StartNew<bool>(() => 
    {
         //send
    });
}

 

本地直接debug运行,无异常,短信发送成功。

然而更新到服务器上,在该操作执行两次左右的时候,进程崩溃重启,应用程序日志如下:

An unhandled exception occurred and the process was terminated.

Application ID: /LM/W3SVC/2/ROOT

Process ID: 3308

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()

 

stackoverflow上也有人遇到过这种问题,但没有比较好的解决方案,目前我将调用发送短信方法写成如下,暂时解决问题,但着实别扭:

Task.Factory.StartNew(() =>
{
    MessageManager.SendMessageAsync(numbers, message);
});

 

请问各位有无类似经验,谢谢!

zucker1988的主页 zucker1988 | 小虾三级 | 园豆:586
提问于:2014-06-20 13:26
< >
分享
最佳答案
0

把 await 去掉。

收获园豆:30
Launcher | 高人七级 |园豆:45050 | 2014-06-20 13:32

不能去掉的吧,需要返回,去掉的话return的是Task<bool>了

zucker1988 | 园豆:586 (小虾三级) | 2014-06-20 13:37

@l3oz: 你不是不需要等待吗?

//异步发送短信,不等待
MessageManager.SendMessageAsync(numbers, message);  

Launcher | 园豆:45050 (高人七级) | 2014-06-20 13:41

@Launcher: 这个是个公共组件,有些调用方需要等待,我这个需求不需要

zucker1988 | 园豆:586 (小虾三级) | 2014-06-20 13:42

@l3oz: 是挺别扭,估计是对异步编程不熟练造成的。我建议的做法是:

bool SendMessage(xxxx,xxxx);

Task<bool> SendMessageAsync(xxxxx,xxxxx){ return Task.Factory.StartNew<bool>(() =>{return SendMessage(xxx,xxx)});}

需要等待的地方可以直接调用 SendMessage,或者:

1,await SendMessageAsync(xxx,xxx);

2, SendMessageAsync(xxx,xxx).Wait();

不需要等待的地方直接调用 SendMessageAsync(xxx,xxx);

 

你这里的主要问题出在你调用 SendMessageAsync(xxx,xxx) 的方法不是 async 的,上面的修改就是通过返回 Task<T> 保留可以使用 await 的空间。

Launcher | 园豆:45050 (高人七级) | 2014-06-20 14:07

@Launcher: 谢谢,明白很多!

zucker1988 | 园豆:586 (小虾三级) | 2014-06-20 14:32
其他回答(3)
0

首先async和await的确应该去掉。其次估计就是context问题了,应该可以朝这个方向研究。

收获园豆:10
Jeffrey Zhao | 园豆:1629 (小虾三级) | 2014-06-20 14:09

感谢老赵!

支持(0) 反对(0) zucker1988 | 园豆:586 (小虾三级) | 2014-06-20 14:32
0

建议使用SemaphoreSlim。

读一下这篇文章Best Practices in Asynchronous Programming,相信问题就能解决。

收获园豆:10
dudu | 园豆:30257 (高人七级) | 2014-06-20 14:13

另外建议加上ConfigureAwait(false)试试:

return await Task.Factory.StartNew<bool>(() =>
{
    //send
}).ConfigureAwait(false);

 

支持(0) 反对(0) dudu | 园豆:30257 (高人七级) | 2014-06-20 14:16

@dudu: 十分感谢!文章会仔细看

支持(0) 反对(0) zucker1988 | 园豆:586 (小虾三级) | 2014-06-20 14:32
0

建议把与第三方通讯的部分和核心业务(数据处理部分)分开,lock可以锁数处理部分,但要注意数据方面的死锁问题,对于第三方通讯部分没必要去加锁限制,因为咱们也没法去决定人家的程序。

张占岭 | 园豆:464 (菜鸟二级) | 2015-03-11 11:56
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册