HttpClient GetAsync 配置 Webjob 处理程序
HttpClient GetAsync disposes Webjob handler
我正在实施 Azure WebJob,当由 Service Bus Message 触发时,它会执行 async API 调用 到外部网络服务。执行 web 请求后,我的 webjob 发生了一些奇怪的事情,inputMessage 已在方法结束前被处理。
下面是演示问题 + 输出的基本示例。
public async void HandleTestQueueMessage([ServiceBusTrigger("%TestQueue%")] BrokeredMessage inputMessage) {
Console.WriteLine($"Received message {inputMessage.MessageId}.");
Console.WriteLine("Starting web request.");
await TestHttpClientAsync();
Console.WriteLine("Finished web request.");
await inputMessage.CompleteAsync(); // --> Exception occurs here
Console.WriteLine($"Completed message {inputMessage.MessageId}.");
}
private async Task TestHttpClientAsync() {
var httpClient = new HttpClient();
var response = await httpClient.GetAsync("http://google.com");
Console.WriteLine($"Got response, statuscode={response.StatusCode}.");
}
控制台输出:
Executing: 'ProblemTestHandler.HandleTestQueueMessage' - Reason: 'New ServiceBus message detected on 'TestQueue'.'
Received message a17cc4fce8c74b3c9f1b8f1a73b4ba1b.
Starting web request.
Executed: 'ProblemTestHandler.HandleTestQueueMessage' (Succeeded)
Got response, statuscode=OK.
Finished web request.
Unhandled Exception: System.ObjectDisposedException: BrokeredMessage has been disposed.
at Microsoft.ServiceBus.Messaging.BrokeredMessage.ThrowIfDisposed()
at Microsoft.ServiceBus.Messaging.BrokeredMessage.BeginComplete(AsyncCallback callback, Object state)
at System.Threading.Tasks.TaskFactory`1.FromAsyncImpl(Func`3 beginMethod, Func`2 endFunction, Action`1 endAction, Object state, TaskCreationOptions creationOptions)
at Microsoft.ServiceBus.Common.Parallel.TaskHelpers.CreateTask(Func`3 begin, Action`1 end, Object state)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at Wkb.eInvoicing.Worker.Handlers.ProblemTestHandler.<HandleTestQueueMessage>d__1.MoveNext() in C:\Dev\eInvoicing\src\Wkb.eInvoicing.Worker\Handlers\ProblemTestHandler.cs:line 43
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<>c.<ThrowAsync>b__6_1(Object state)
at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)
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()
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
正如您在输出中看到的,我的 JobHost 容器认为该方法在 httpClient.GetAsync() 方法执行后立即成功完成:
Starting web request.
Executed: 'ProblemTestHandler.HandleTestQueueMessage' (Succeeded)
Got response, statuscode=OK.
当我用非异步替代方法(例如使用 RestSharp)替换 Web 请求时,问题没有发生。有什么想法可能是此问题的根本原因吗?
你几乎不应该使用 async void
除非你正在编写一个事件处理程序,你应该使用 async Task
相反,这会让系统知道你的 webjob 还没有完成所以它不会尝试在完成之前强制关闭资源。
我正在实施 Azure WebJob,当由 Service Bus Message 触发时,它会执行 async API 调用 到外部网络服务。执行 web 请求后,我的 webjob 发生了一些奇怪的事情,inputMessage 已在方法结束前被处理。 下面是演示问题 + 输出的基本示例。
public async void HandleTestQueueMessage([ServiceBusTrigger("%TestQueue%")] BrokeredMessage inputMessage) {
Console.WriteLine($"Received message {inputMessage.MessageId}.");
Console.WriteLine("Starting web request.");
await TestHttpClientAsync();
Console.WriteLine("Finished web request.");
await inputMessage.CompleteAsync(); // --> Exception occurs here
Console.WriteLine($"Completed message {inputMessage.MessageId}.");
}
private async Task TestHttpClientAsync() {
var httpClient = new HttpClient();
var response = await httpClient.GetAsync("http://google.com");
Console.WriteLine($"Got response, statuscode={response.StatusCode}.");
}
控制台输出:
Executing: 'ProblemTestHandler.HandleTestQueueMessage' - Reason: 'New ServiceBus message detected on 'TestQueue'.'
Received message a17cc4fce8c74b3c9f1b8f1a73b4ba1b.
Starting web request.
Executed: 'ProblemTestHandler.HandleTestQueueMessage' (Succeeded)
Got response, statuscode=OK.
Finished web request.
Unhandled Exception: System.ObjectDisposedException: BrokeredMessage has been disposed.
at Microsoft.ServiceBus.Messaging.BrokeredMessage.ThrowIfDisposed()
at Microsoft.ServiceBus.Messaging.BrokeredMessage.BeginComplete(AsyncCallback callback, Object state)
at System.Threading.Tasks.TaskFactory`1.FromAsyncImpl(Func`3 beginMethod, Func`2 endFunction, Action`1 endAction, Object state, TaskCreationOptions creationOptions)
at Microsoft.ServiceBus.Common.Parallel.TaskHelpers.CreateTask(Func`3 begin, Action`1 end, Object state)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at Wkb.eInvoicing.Worker.Handlers.ProblemTestHandler.<HandleTestQueueMessage>d__1.MoveNext() in C:\Dev\eInvoicing\src\Wkb.eInvoicing.Worker\Handlers\ProblemTestHandler.cs:line 43
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<>c.<ThrowAsync>b__6_1(Object state)
at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)
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()
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
正如您在输出中看到的,我的 JobHost 容器认为该方法在 httpClient.GetAsync() 方法执行后立即成功完成:
Starting web request.
Executed: 'ProblemTestHandler.HandleTestQueueMessage' (Succeeded)
Got response, statuscode=OK.
当我用非异步替代方法(例如使用 RestSharp)替换 Web 请求时,问题没有发生。有什么想法可能是此问题的根本原因吗?
你几乎不应该使用 async void
除非你正在编写一个事件处理程序,你应该使用 async Task
相反,这会让系统知道你的 webjob 还没有完成所以它不会尝试在完成之前强制关闭资源。