В следующем коде в строке Task.WhenAll
возникает тупик:
[Fact]
public async Task GetLdapEntries_ReturnsLdapEntries()
{
var ldapEntries = _fixture.CreateMany<LdapEntryDto>(2).ToList();
var creationTasks = new List<Task>();
foreach (var led in ldapEntries)
{
var task = _attributesServiceClient.CreateLdapEntry(led);
creationTasks.Add(task);
}
await Task.WhenAll(creationTasks); // <- deadlock here
var result = await _ldapAccess.GetLdapEntries();
result.Should().BeEquivalentTo(ldapEntries);
}
public async Task<LdapEntryDto> CreateLdapEntry(LdapEntryDto ldapEntryDto)
{
using (var creationResponse = await _httpClient.PostAsJsonAsync<LdapEntryDto>("", ldapEntryDto))
{
if (creationResponse.StatusCode == HttpStatusCode.Created)
{
return await creationResponse.Content.ReadAsAsync<LdapEntryDto>();
}
return null;
}
}
Тест xUnit пытается создать тестовые данные асинхронно, вызывая асинхронный метод, который сам await
sa отвечает извеб-сервис._httpClient
- это реальное HttpClient
, созданное из памяти TestServer
через TestServer.CreateClient()
.
При установке точки останова на using line
в методе CreateLdapEntry
Хит дважды.Точка останова при проверке кода состояния никогда не срабатывает.При взломе Task.WhenAll()
и проверке creationTasks
обе задачи находятся в состоянии WaitingForActivation
:
creationTasks
Count = 2
[0]: Id = 32, Status = WaitingForActivation, Method = "{null}", Result = "{Not yet computed}"
[1]: Id = 33, Status = WaitingForActivation, Method = "{null}", Result = "{Not yet computed}"
Если вы не используете Task.WhenAll()
, а вместо этого ожидаете каждую задачу в отдельности, тупик не возникает:
foreach (var led in ldapEntries)
{
await _attributesServiceClient.CreateLdapEntry(led);
}
Мне известно, что подобный вопрос был задан и получен ответ, однако примеры кода там используют .Result
, а не await Task.WhenAll()
.
IХотелось бы понять, почему возникает эта тупиковая ситуация при использовании Task.WhenAll()
.
РЕДАКТИРОВАТЬ: добавлен стек вызовов заблокированных потоков
Not Flagged 3992 11 Worker Thread Worker Thread Microsoft.AspNetCore.Routing.dll!Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke
[Managed to Native Transition]
Microsoft.AspNetCore.Routing.dll!Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(Microsoft.AspNetCore.Http.HttpContext httpContext)
ShibbolethAttributes.Service.dll!RoleManager.Service.Middleware.ApiKeyHandlerMiddleware.Invoke(Microsoft.AspNetCore.Http.HttpContext context) Line 38
Microsoft.AspNetCore.Diagnostics.dll!Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(Microsoft.AspNetCore.Http.HttpContext context)
System.Private.CoreLib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.Startd__7>(ref Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.d__7 stateMachine)
Microsoft.AspNetCore.Diagnostics.dll!Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(Microsoft.AspNetCore.Http.HttpContext context)
Microsoft.AspNetCore.Hosting.dll!Microsoft.AspNetCore.Hosting.Internal.HostingApplication.ProcessRequestAsync(Microsoft.AspNetCore.Hosting.Internal.HostingApplication.Context context)
Microsoft.AspNetCore.TestHost.dll!Microsoft.AspNetCore.TestHost.TestServer.ApplicationWrapper.ProcessRequestAsync(Microsoft.AspNetCore.Hosting.Internal.HostingApplication.Context context)
Microsoft.AspNetCore.TestHost.dll!Microsoft.AspNetCore.TestHost.HttpContextBuilder.SendAsync.AnonymousMethod__0()
System.Private.CoreLib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.Startc__DisplayClass10_0.b__0>d stateMachine)
Microsoft.AspNetCore.TestHost.dll!Microsoft.AspNetCore.TestHost.HttpContextBuilder.SendAsync.AnonymousMethod__0()
System.Private.CoreLib.dll!System.Threading.Tasks.Task.InnerInvoke()
System.Private.CoreLib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state)
System.Private.CoreLib.dll!System.Threading.Tasks.Task.ExecuteWithThreadLocal(ref System.Threading.Tasks.Task currentTaskSlot)
System.Private.CoreLib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch()
Not Flagged 1496 10 Worker Thread Worker Thread Microsoft.AspNetCore.Routing.dll!Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke
Microsoft.AspNetCore.Routing.dll!Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(Microsoft.AspNetCore.Http.HttpContext httpContext)
ShibbolethAttributes.Service.dll!RoleManager.Service.Middleware.ApiKeyHandlerMiddleware.Invoke(Microsoft.AspNetCore.Http.HttpContext context) Line 38
Microsoft.AspNetCore.Diagnostics.dll!Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(Microsoft.AspNetCore.Http.HttpContext context)
System.Private.CoreLib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.Startd__7>(ref Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.d__7 stateMachine)
Microsoft.AspNetCore.Diagnostics.dll!Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(Microsoft.AspNetCore.Http.HttpContext context)
Microsoft.AspNetCore.Hosting.dll!Microsoft.AspNetCore.Hosting.Internal.HostingApplication.ProcessRequestAsync(Microsoft.AspNetCore.Hosting.Internal.HostingApplication.Context context)
Microsoft.AspNetCore.TestHost.dll!Microsoft.AspNetCore.TestHost.TestServer.ApplicationWrapper.ProcessRequestAsync(Microsoft.AspNetCore.Hosting.Internal.HostingApplication.Context context)
Microsoft.AspNetCore.TestHost.dll!Microsoft.AspNetCore.TestHost.HttpContextBuilder.SendAsync.AnonymousMethod__0()
System.Private.CoreLib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.Startc__DisplayClass10_0.b__0>d stateMachine)
Microsoft.AspNetCore.TestHost.dll!Microsoft.AspNetCore.TestHost.HttpContextBuilder.SendAsync.AnonymousMethod__0()
System.Private.CoreLib.dll!System.Threading.Tasks.Task.InnerInvoke()
System.Private.CoreLib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state)
System.Private.CoreLib.dll!System.Threading.Tasks.Task.ExecuteWithThreadLocal(ref System.Threading.Tasks.Task currentTaskSlot)
System.Private.CoreLib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch()