簡體   English   中英

如何捕獲第三方庫中未等待的任務引發的異常?

[英]How to catch exception thrown by a task that's not awaited in a third party library?

我有一個依賴於第三方庫EasyRedisMQ的 Windows 服務(使用 Topshelf)。 不幸的是,我剛剛在其中一個庫方法中發現了以下代碼:

    public async Task InitializeAsync()
    {
        if (SubscriberInfo == null) throw new NullReferenceException("SubscriberInfo is required.");
        if (string.IsNullOrWhiteSpace(SubscriberInfo.SubscriberId)) throw new NullReferenceException("SubscriberId is required");
        if (string.IsNullOrWhiteSpace(SubscriberInfo.ExchangeName)) throw new NullReferenceException("ExchangeName is required");
        if (string.IsNullOrWhiteSpace(SubscriberInfo.QueueName)) throw new NullReferenceException("QueueName is required");
        if (OnMessageAsync == null) throw new NullReferenceException("OnMessageAsync is required");

        await _cacheClient.SubscribeAsync<string>(SubscriberInfo.ExchangeName, DoWorkAsync);

        DoWorkAsync("").FireAndForget();
    }

這里 DoWorkAsync 返回一個任務,但正如 FireAndForget 指出的那樣,不幸的是沒有等待。 實際上,FireAndForget 是一個具有空主體的方法(唯一的目的是明確表示不等待任務)。 這里查看完整的源代碼。

問題是DoWorkAsync偶爾會拋出異常,導致服務崩潰:

{
  "Depth": 0,
  "ClassName": "StackExchange.Redis.RedisConnectionException",
  "Message": "SocketFailure on RPOP",
  "Source": "mscorlib",
  "StackTraceString": "   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at StackExchange.Redis.Extensions.Core.StackExchangeRedisCacheClient.<ListGetFromRightAsync>d__67`1.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at EasyRedisMQ.Models.Subscriber`1.<GetNextMessageAsync>d__12.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at EasyRedisMQ.Models.Subscriber`1.<DoWorkAsync>d__13.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at StackExchange.Redis.Extensions.Core.StackExchangeRedisCacheClient.<>c__DisplayClass59_0`1.<<SubscribeAsync>b__0>d.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<>c.<ThrowAsync>b__6_1(Object state)\r\n   at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)\r\n   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)\r\n   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)\r\n   at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()\r\n   at System.Threading.ThreadPoolWorkQueue.Dispatch()\r\n   at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()",
...
}

我非常想捕獲異常(因為它實際上是無害的,只需重試操作即可)。 但是,在閱讀了這個 StackOverflow 問題並嘗試了 AppDomain.CurrentDomain.FirstChanceException 之后,我並不抱太大希望。 FirstChanceException 的問題在於它發生在 Tophelf 的外部

HostFactory.Run(hostConfigurator => { ... }

方法,其中我引用了服務(業務邏輯所在的位置):

hostConfigurator.Service<IConsumer>(serviceConfigurator =>
{
    serviceConfigurator.ConstructUsing(() => IocContainer.IocContainer.Instance.Resolve<IConsumer>());
    serviceConfigurator.WhenStarted(consumer => { /* Here I have control */ });
    ...
}

有沒有人對如何處理這種情況有任何想法?

訂閱 TaskScheduler 的事件

TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
//...

private void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
    e.SetObserved();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM