Skip to content

Commit 0defbf7

Browse files
authored
Fix flakiness in Kestrel ungraceful shutdown test (#6637)
1 parent d9bc52b commit 0defbf7

File tree

2 files changed

+38
-4
lines changed

2 files changed

+38
-4
lines changed

src/Servers/Kestrel/shared/test/TestApplicationErrorLogger.cs

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
55
using System.Collections.Concurrent;
66
using System.Collections.Generic;
77
using System.Linq;
8+
using System.Threading.Tasks;
89
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
910
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
1011
using Microsoft.Extensions.Logging;
@@ -16,6 +17,9 @@ public class TestApplicationErrorLogger : ILogger
1617
// Application errors are logged using 13 as the eventId.
1718
private const int ApplicationErrorEventId = 13;
1819

20+
private Func<LogMessage, bool> _messageFilter;
21+
private TaskCompletionSource<LogMessage> _messageFilterTcs;
22+
1923
public List<Type> IgnoredExceptions { get; } = new List<Type>();
2024

2125
public bool ThrowOnCriticalErrors { get; set; } = true;
@@ -32,6 +36,19 @@ public class TestApplicationErrorLogger : ILogger
3236

3337
public int ApplicationErrorsLogged => Messages.Count(message => message.EventId.Id == ApplicationErrorEventId);
3438

39+
public Task<LogMessage> WaitForMessage(Func<LogMessage, bool> messageFilter)
40+
{
41+
if (_messageFilterTcs != null)
42+
{
43+
throw new InvalidOperationException($"{nameof(WaitForMessage)} cannot be called concurrently.");
44+
}
45+
46+
_messageFilterTcs = new TaskCompletionSource<LogMessage>(TaskCreationOptions.RunContinuationsAsynchronously);
47+
_messageFilter = messageFilter;
48+
49+
return _messageFilterTcs.Task;
50+
}
51+
3552
public IDisposable BeginScope<TState>(TState state)
3653
{
3754
Scopes.Enqueue(state);
@@ -77,13 +94,21 @@ public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Except
7794
throw new Exception($"Unexpected connection error. {log}");
7895
}
7996

80-
Messages.Enqueue(new LogMessage
97+
var logMessage = new LogMessage
8198
{
8299
LogLevel = logLevel,
83100
EventId = eventId,
84101
Exception = exception,
85102
Message = formatter(state, exception)
86-
});
103+
};
104+
105+
Messages.Enqueue(logMessage);
106+
107+
if (_messageFilter?.Invoke(logMessage) == true)
108+
{
109+
_messageFilterTcs.TrySetResult(logMessage);
110+
_messageFilterTcs = null;
111+
}
87112
}
88113

89114
public class LogMessage

src/Servers/Kestrel/test/FunctionalTests/Http2/ShutdownTests.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,16 @@ public async Task GracefulTurnsAbortiveIfRequestsDoNotFinish()
134134
Assert.False(requestTask.IsCompleted);
135135
await requestStarted.Task.DefaultTimeout();
136136

137-
await server.StopAsync(new CancellationToken(true)).DefaultTimeout();
137+
// Wait for the graceful shutdown log before canceling the token passed to StopAsync and triggering an ungraceful shutdown.
138+
// Otherwise, graceful shutdown might be skipped causing there to be no corresponding log. https://github.com/aspnet/AspNetCore/issues/6556
139+
var closingMessageTask = TestApplicationErrorLogger.WaitForMessage(m => m.Message.Contains("is closing.")).DefaultTimeout();
140+
141+
var cts = new CancellationTokenSource();
142+
var stopServerTask = server.StopAsync(cts.Token).DefaultTimeout();
143+
144+
await closingMessageTask;
145+
cts.Cancel();
146+
await stopServerTask;
138147
}
139148

140149
Assert.Contains(TestApplicationErrorLogger.Messages, m => m.Message.Contains("is closing."));

0 commit comments

Comments
 (0)