public async Task ConnectionNotTimedOutWhileRequestBeingSent() { var testContext = new TestServiceContext(LoggerFactory); var heartbeatManager = new HeartbeatManager(testContext.ConnectionManager); using (var server = CreateServer(testContext)) using (var connection = server.CreateConnection()) { await connection.Send( "POST /consume HTTP/1.1", "Host:", "Transfer-Encoding: chunked", "", ""); await _firstRequestReceived.Task.DefaultTimeout(); for (var totalDelay = TimeSpan.Zero; totalDelay < _longDelay; totalDelay += _shortDelay) { await connection.Send( "1", "a", ""); testContext.MockSystemClock.UtcNow += _shortDelay; heartbeatManager.OnHeartbeat(testContext.SystemClock.UtcNow); } await connection.Send( "0", "", ""); await ReceiveResponse(connection, testContext); } }
/// <summary> /// 正在初始化心跳模块 /// </summary> private static void InitHeartbeat() { //LogHelper.SystemInfo("正在初始化心跳检测模块"); _heartbeatManager = new HeartbeatManager(_heartbeatInterval); _heartbeatManager.Start(); }
private async Task KeepAliveTimeoutDoesNotApplyToUpgradedConnections() { var testContext = new TestServiceContext(LoggerFactory); var heartbeatManager = new HeartbeatManager(testContext.ConnectionManager); var cts = new CancellationTokenSource(); using (var server = CreateServer(testContext, upgradeCt: cts.Token)) using (var connection = server.CreateConnection()) { await connection.Send( "GET /upgrade HTTP/1.1", "Host:", "Connection: Upgrade", "", ""); await connection.Receive( "HTTP/1.1 101 Switching Protocols", "Connection: Upgrade", $"Date: {testContext.DateHeaderValue}", "", ""); for (var totalDelay = TimeSpan.Zero; totalDelay < _longDelay; totalDelay += _shortDelay) { testContext.MockSystemClock.UtcNow += _shortDelay; heartbeatManager.OnHeartbeat(testContext.SystemClock.UtcNow); } cts.Cancel(); await connection.Receive("hello, world"); } }
private async Task ConnectionNotTimedOutWhileAppIsRunning() { var testContext = new TestServiceContext(LoggerFactory); var heartbeatManager = new HeartbeatManager(testContext.ConnectionManager); var cts = new CancellationTokenSource(); using (var server = CreateServer(testContext, longRunningCt: cts.Token)) using (var connection = server.CreateConnection()) { await connection.Send( "GET /longrunning HTTP/1.1", "Host:", "", ""); await _firstRequestReceived.Task.DefaultTimeout(); for (var totalDelay = TimeSpan.Zero; totalDelay < _longDelay; totalDelay += _shortDelay) { testContext.MockSystemClock.UtcNow += _shortDelay; heartbeatManager.OnHeartbeat(testContext.SystemClock.UtcNow); } cts.Cancel(); await ReceiveResponse(connection, testContext); await connection.Send( "GET / HTTP/1.1", "Host:", "", ""); await ReceiveResponse(connection, testContext); } }
public async Task RequestHeadersTimeoutCanceledAfterHeadersReceived() { var testContext = new TestServiceContext(LoggerFactory); var heartbeatManager = new HeartbeatManager(testContext.ConnectionManager); await using (var server = CreateServer(testContext)) { using (var connection = server.CreateConnection()) { await connection.TransportConnection.WaitForReadTask; await connection.Send( "POST / HTTP/1.1", "Host:", "Content-Length: 1", "", ""); // Min amount of time between requests that triggers a request headers timeout. testContext.MockSystemClock.UtcNow += RequestHeadersTimeout + Heartbeat.Interval + TimeSpan.FromTicks(1); heartbeatManager.OnHeartbeat(testContext.SystemClock.UtcNow); await connection.Send( "a"); await ReceiveResponse(connection, testContext); } } }
public async Task ConnectionClosedWhenKeepAliveTimeoutExpires() { var testContext = new TestServiceContext(LoggerFactory); var heartbeatManager = new HeartbeatManager(testContext.ConnectionManager); await using (var server = CreateServer(testContext)) { using (var connection = server.CreateConnection()) { await connection.TransportConnection.WaitForReadTask; await connection.Send( "GET / HTTP/1.1", "Host:", "", ""); await ReceiveResponse(connection, testContext); // Min amount of time between requests that triggers a keep-alive timeout. testContext.MockSystemClock.UtcNow += _keepAliveTimeout + Heartbeat.Interval + TimeSpan.FromTicks(1); heartbeatManager.OnHeartbeat(testContext.SystemClock.UtcNow); await connection.WaitForConnectionClose(); } } }
public async Task TimeoutNotResetOnEachRequestLineCharacterReceived() { var testContext = new TestServiceContext(LoggerFactory); var heartbeatManager = new HeartbeatManager(testContext.ConnectionManager); // Disable response rate, so we can finish the send loop without timing out the response. testContext.ServerOptions.Limits.MinResponseDataRate = null; await using (var server = CreateServer(testContext)) { using (var connection = server.CreateConnection()) { await connection.TransportConnection.WaitForReadTask; foreach (var ch in "POST / HTTP/1.1\r\nHost:\r\n\r\n") { await connection.Send(ch.ToString()); testContext.MockSystemClock.UtcNow += ShortDelay; heartbeatManager.OnHeartbeat(testContext.SystemClock.UtcNow); } await ReceiveTimeoutResponse(connection, testContext); await connection.WaitForConnectionClose(); } } }
public async Task ConnectionKeptAliveBetweenRequests() { var testContext = new TestServiceContext(LoggerFactory); var heartbeatManager = new HeartbeatManager(testContext.ConnectionManager); await using (var server = CreateServer(testContext)) { using (var connection = server.CreateConnection()) { await connection.TransportConnection.WaitForReadTask; for (var i = 0; i < 10; i++) { await connection.Send( "GET / HTTP/1.1", "Host:", "", ""); await ReceiveResponse(connection, testContext); // Max amount of time between requests that doesn't trigger a keep-alive timeout. testContext.MockSystemClock.UtcNow += _keepAliveTimeout + Heartbeat.Interval; heartbeatManager.OnHeartbeat(testContext.SystemClock.UtcNow); } } } }
public async Task DoesNotEnforceRequestBodyMinimumDataRateOnUpgradedRequest() { var appEvent = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously); var delayEvent = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously); var serviceContext = new TestServiceContext(LoggerFactory); var heartbeatManager = new HeartbeatManager(serviceContext.ConnectionManager); using (var server = new TestServer(async context => { context.Features.Get <IHttpMinRequestBodyDataRateFeature>().MinDataRate = new MinDataRate(bytesPerSecond: double.MaxValue, gracePeriod: Heartbeat.Interval + TimeSpan.FromTicks(1)); using (var stream = await context.Features.Get <IHttpUpgradeFeature>().UpgradeAsync()) { appEvent.SetResult(null); // Read once to go through one set of TryPauseTimingReads()/TryResumeTimingReads() calls await stream.ReadAsync(new byte[1], 0, 1); await delayEvent.Task.DefaultTimeout(); // Read again to check that the connection is still alive await stream.ReadAsync(new byte[1], 0, 1); // Send a response to distinguish from the timeout case where the 101 is still received, but without any content var response = Encoding.ASCII.GetBytes("hello"); await stream.WriteAsync(response, 0, response.Length); } }, serviceContext)) { using (var connection = server.CreateConnection()) { await connection.Send( "GET / HTTP/1.1", "Host:", "Connection: upgrade", "", "a"); await appEvent.Task.DefaultTimeout(); serviceContext.MockSystemClock.UtcNow += TimeSpan.FromSeconds(5); heartbeatManager.OnHeartbeat(serviceContext.SystemClock.UtcNow); delayEvent.SetResult(null); await connection.Send("b"); await connection.ReceiveEnd( "HTTP/1.1 101 Switching Protocols", "Connection: Upgrade", $"Date: {server.Context.DateHeaderValue}", "", "hello"); } await server.StopAsync(); } }
public async Task ConnectionClosedWhenResponseNotDrainedAtMinimumDataRate(ListenOptions listenOptions) { var testContext = new TestServiceContext(LoggerFactory); var heartbeatManager = new HeartbeatManager(testContext.ConnectionManager); var minRate = new MinDataRate(16384, TimeSpan.FromSeconds(2)); await using (var server = new TestServer(context => { context.Features.Get <IHttpMinResponseDataRateFeature>().MinDataRate = minRate; return(Task.CompletedTask); }, testContext, listenOptions)) { using (var connection = server.CreateConnection()) { var transportConnection = connection.TransportConnection; var outputBufferedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); #pragma warning disable 0618 // TODO: Repalce OnWriterCompleted transportConnection.Output.OnWriterCompleted((ex, state) => { ((TaskCompletionSource)state).SetResult(); }, outputBufferedTcs); #pragma warning restore await connection.Send( "GET / HTTP/1.1", "Host:", "Connection: close", "", ""); // Wait for the drain timeout to be set. await outputBufferedTcs.Task.DefaultTimeout(); // Advance the clock to the grace period for (var i = 0; i < 2; i++) { testContext.MockSystemClock.UtcNow += TimeSpan.FromSeconds(1); heartbeatManager.OnHeartbeat(testContext.SystemClock.UtcNow); } testContext.MockSystemClock.UtcNow += Heartbeat.Interval - TimeSpan.FromSeconds(.5); heartbeatManager.OnHeartbeat(testContext.SystemClock.UtcNow); Assert.Null(transportConnection.AbortReason); testContext.MockSystemClock.UtcNow += TimeSpan.FromSeconds(1); heartbeatManager.OnHeartbeat(testContext.SystemClock.UtcNow); Assert.NotNull(transportConnection.AbortReason); Assert.Equal(CoreStrings.ConnectionTimedBecauseResponseMininumDataRateNotSatisfied, transportConnection.AbortReason.Message); Assert.Single(LogMessages, w => w.EventId.Id == 28 && w.LogLevel <= LogLevel.Debug); } } }
private static ServiceContext CreateServiceContext(IOptions <KestrelServerOptions> options, ILoggerFactory loggerFactory) { if (options == null) { throw new ArgumentNullException(nameof(options)); } if (loggerFactory == null) { throw new ArgumentNullException(nameof(loggerFactory)); } var serverOptions = options.Value ?? new KestrelServerOptions(); var logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Server.Kestrel"); var trace = new KestrelTrace(logger); var connectionManager = new ConnectionManager( trace, serverOptions.Limits.MaxConcurrentUpgradedConnections); var now = DateTimeOffset.UtcNow; var heartbeatManager = new HeartbeatManager(connectionManager, now); var dateHeaderValueManager = new DateHeaderValueManager(now); var heartbeat = new Heartbeat( new IHeartbeatHandler[] { dateHeaderValueManager, heartbeatManager }, new SystemClock(), DebuggerWrapper.Singleton, trace); // TODO: This logic will eventually move into the IConnectionHandler<T> and off // the service context once we get to https://github.com/aspnet/KestrelHttpServer/issues/1662 PipeScheduler scheduler = null; switch (serverOptions.ApplicationSchedulingMode) { case SchedulingMode.Default: case SchedulingMode.ThreadPool: scheduler = PipeScheduler.ThreadPool; break; case SchedulingMode.Inline: scheduler = PipeScheduler.Inline; break; default: throw new NotSupportedException(CoreStrings.FormatUnknownTransportMode(serverOptions.ApplicationSchedulingMode)); } return(new ServiceContext { Log = trace, HttpParser = new HttpParser <Http1ParsingHandler>(trace.IsEnabled(LogLevel.Information)), Scheduler = scheduler, SystemClock = heartbeatManager, DateHeaderValueManager = dateHeaderValueManager, ConnectionManager = connectionManager, Heartbeat = heartbeat, ServerOptions = serverOptions, }); }
public HtcServer(HtcServerOptions serverOptions) { ServerOptions = serverOptions; HtcLogger = new HtcLogger(Logger); ConnectionManager = new ConnectionManager(HtcLogger, ServerOptions.Limits.MaxConcurrentUpgradedConnections); HeartbeatManager = new HeartbeatManager(ConnectionManager); Heartbeat = new Heartbeat(new IHeartbeatHandler[] { dateHeaderValueManager, heartbeatManager }, new SystemClock(), DebuggerWrapper.Singleton, trace); HttpCharacters.Initialize(); }
public MembershipManager(IShard shard, NodeContext context, ClusterConfigurationManager clusterConfigMgr) { this._shard = shard; this._context = context; this._clusterConfigMgr = clusterConfigMgr; this._strategy = new ElectionBasedMembershipStrategy(shard, context, _heartbeatReporting, _clusterConfigMgr); shard.RegisterShardListener(Common.MiscUtil.MEMBERSHIP_MANAGER, this); _heartbeatManager = new HeartbeatManager(); _latestMembership.Cluster = _context.ClusterName; _latestMembership.Shard = _context.LocalShardName; }
public async Task ConnectionClosedWhenResponseNotDrainedAtMinimumDataRate(ListenOptions listenOptions) { var testContext = new TestServiceContext(LoggerFactory); var heartbeatManager = new HeartbeatManager(testContext.ConnectionManager); var minRate = new MinDataRate(16384, TimeSpan.FromSeconds(2)); using (var server = new TestServer(context => { context.Features.Get <IHttpMinResponseDataRateFeature>().MinDataRate = minRate; return(Task.CompletedTask); }, testContext, listenOptions)) { using (var connection = server.CreateConnection()) { var transportConnection = connection.TransportConnection; var outputBufferedTcs = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously); transportConnection.Output.OnWriterCompleted((ex, state) => { ((TaskCompletionSource <object>)state).SetResult(null); }, outputBufferedTcs); await connection.Send( "GET / HTTP/1.1", "Host:", "Connection: close", "", ""); // Wait for the drain timeout to be set. await outputBufferedTcs.Task.DefaultTimeout(); testContext.MockSystemClock.UtcNow += Heartbeat.Interval + TimeSpan.FromSeconds(testContext.ServerOptions.Limits.MaxResponseBufferSize.Value * 2 / minRate.BytesPerSecond); heartbeatManager.OnHeartbeat(testContext.SystemClock.UtcNow); Assert.Null(transportConnection.AbortReason); testContext.MockSystemClock.UtcNow += TimeSpan.FromTicks(1); heartbeatManager.OnHeartbeat(testContext.SystemClock.UtcNow); Assert.NotNull(transportConnection.AbortReason); Assert.Equal(CoreStrings.ConnectionTimedBecauseResponseMininumDataRateNotSatisfied, transportConnection.AbortReason.Message); Assert.Single(TestApplicationErrorLogger.Messages, w => w.EventId.Id == 28 && w.LogLevel == LogLevel.Information); } } }
public async Task HandshakeTimesOutAndIsLoggedAsDebug() { var loggerProvider = new HandshakeErrorLoggerProvider(); LoggerFactory.AddProvider(loggerProvider); var testContext = new TestServiceContext(LoggerFactory) { ExpectedConnectionMiddlewareCount = 1 }; var heartbeatManager = new HeartbeatManager(testContext.ConnectionManager); var handshakeStartedTcs = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously); TimeSpan handshakeTimeout = default; await using (var server = new TestServer(context => Task.CompletedTask, testContext, listenOptions => { listenOptions.UseHttps(o => { o.ServerCertificate = new X509Certificate2(TestResources.GetTestCertificate()); o.OnAuthenticate = (_, __) => { handshakeStartedTcs.SetResult(null); }; handshakeTimeout = o.HandshakeTimeout; }); })) { using (var connection = server.CreateConnection()) { // HttpsConnectionAdapter dispatches via Task.Run() before starting the handshake. // Wait for the handshake to start before advancing the system clock. await handshakeStartedTcs.Task.DefaultTimeout(); // Min amount of time between requests that triggers a handshake timeout. testContext.MockSystemClock.UtcNow += handshakeTimeout + Heartbeat.Interval + TimeSpan.FromTicks(1); heartbeatManager.OnHeartbeat(testContext.SystemClock.UtcNow); Assert.Equal(0, await connection.Stream.ReadAsync(new byte[1], 0, 1).DefaultTimeout()); } } await loggerProvider.FilterLogger.LogTcs.Task.DefaultTimeout(); Assert.Equal(2, loggerProvider.FilterLogger.LastEventId); Assert.Equal(LogLevel.Debug, loggerProvider.FilterLogger.LastLogLevel); }
/// <summary> /// Program's entry point. /// </summary> /// <param name="args">Commandline arguments.</param> public static void Main(string[] args) { Console.Title = "Gamemakergm's Heartbeater."; new ServerExample("[MCTest] Gamemakergm's Awesome Build", true); // Create a new server for demonstration purposes. Heartbeat = new HeartbeatExample(); // Create the new heartbeat. Manager = new HeartbeatManager(Heartbeat, TimeSpan.FromSeconds(5), ServerExample.Server); // while (true) { if (Console.ReadLine().Equals("h")) { Console.WriteLine("H"); } } }
public void InitializeHeartbeat() { var heartbeatManager = new HeartbeatManager(ConnectionManager); DateHeaderValueManager = new DateHeaderValueManager(); Heartbeat = new Heartbeat( new IHeartbeatHandler[] { DateHeaderValueManager, heartbeatManager }, new SystemClock(), DebuggerWrapper.Singleton, Log); MockSystemClock = null; SystemClock = heartbeatManager; }
private async Task ConnectionTimesOutWhenOpenedButNoRequestSent() { var testContext = new TestServiceContext(LoggerFactory); var heartbeatManager = new HeartbeatManager(testContext.ConnectionManager); using (var server = CreateServer(testContext)) using (var connection = server.CreateConnection()) { // Min amount of time between requests that triggers a keep-alive timeout. testContext.MockSystemClock.UtcNow += _keepAliveTimeout + Heartbeat.Interval + TimeSpan.FromTicks(1); heartbeatManager.OnHeartbeat(testContext.SystemClock.UtcNow); await connection.WaitForConnectionClose(); } }
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); PriceUpdateContext.Initialize(APIConfigManager.AWSAccessKey, APIConfigManager.AWSSecretKey, APIConfigManager.ServiceAccountId, APIConfigManager.ServiceAccountPassword, "smtp.gmail.com", "Automated Mail", APIConfigManager.TablesToCreate); //InitalizePriceUpdateContext(); //Make endpoint and timeout configurable HeartbeatManager hbManager = new HeartbeatManager(@"http://localhost:59132/api/amazonproductapi", new TimeSpan(0, 1, 0)); Task hbTask = Task.Factory.StartNew(hbManager.CheckServiceHeartbeat, TaskCreationOptions.LongRunning); JobScheduler.Start(); }
public async Task ConnectionAbortedWhenRequestLineNotReceivedInTime(string requestLine) { var testContext = new TestServiceContext(LoggerFactory); var heartbeatManager = new HeartbeatManager(testContext.ConnectionManager); using (var server = CreateServer(testContext)) using (var connection = server.CreateConnection()) { await connection.Send(requestLine); // Min amount of time between requests that triggers a request headers timeout. testContext.MockSystemClock.UtcNow += RequestHeadersTimeout + Heartbeat.Interval + TimeSpan.FromTicks(1); heartbeatManager.OnHeartbeat(testContext.SystemClock.UtcNow); await ReceiveTimeoutResponse(connection, testContext); } }
public void Dispose() { if (_heartbeatManager != null) { _heartbeatManager.Dispose(); } _heartbeatManager = null; if (_takeOverElectionTask != null) { _takeOverElectionTask.Stop(); } _takeOverElectionTask = null; if (_retryTask != null) { _retryTask.Stop(); } _retryTask = null; }
public async Task TimeoutNotResetOnEachRequestLineCharacterReceived() { var testContext = new TestServiceContext(LoggerFactory); var heartbeatManager = new HeartbeatManager(testContext.ConnectionManager); using (var server = CreateServer(testContext)) using (var connection = server.CreateConnection()) { foreach (var ch in "POST / HTTP/1.1\r\nHost:\r\n\r\n") { await connection.Send(ch.ToString()); testContext.MockSystemClock.UtcNow += ShortDelay; heartbeatManager.OnHeartbeat(testContext.SystemClock.UtcNow); } await ReceiveTimeoutResponse(connection, testContext); await connection.WaitForConnectionClose(); } }
private static ServiceContext CreateServiceContext(IOptions <KestrelServerOptions> options, ILoggerFactory loggerFactory, DiagnosticSource?diagnosticSource) { if (options == null) { throw new ArgumentNullException(nameof(options)); } if (loggerFactory == null) { throw new ArgumentNullException(nameof(loggerFactory)); } var serverOptions = options.Value ?? new KestrelServerOptions(); var trace = new KestrelTrace(loggerFactory); var connectionManager = new ConnectionManager( trace, serverOptions.Limits.MaxConcurrentUpgradedConnections); var heartbeatManager = new HeartbeatManager(connectionManager); var dateHeaderValueManager = new DateHeaderValueManager(); var heartbeat = new Heartbeat( new IHeartbeatHandler[] { dateHeaderValueManager, heartbeatManager }, new SystemClock(), DebuggerWrapper.Singleton, trace); return(new ServiceContext { Log = trace, Scheduler = PipeScheduler.ThreadPool, HttpParser = new HttpParser <Http1ParsingHandler>(trace.IsEnabled(LogLevel.Information)), SystemClock = heartbeatManager, DateHeaderValueManager = dateHeaderValueManager, ConnectionManager = connectionManager, Heartbeat = heartbeat, ServerOptions = serverOptions, DiagnosticSource = diagnosticSource }); }
public async Task TimeoutNotResetOnEachRequestLineCharacterReceived() { var testContext = new TestServiceContext(LoggerFactory); var heartbeatManager = new HeartbeatManager(testContext.ConnectionManager); using (var server = CreateServer(testContext)) using (var connection = server.CreateConnection()) { // When the in-memory connection is aborted, the input PipeWriter is completed behind the scenes // so eventually connection.Send() throws an InvalidOperationException. await Assert.ThrowsAsync <InvalidOperationException>(async() => { foreach (var ch in "POST / HTTP/1.1\r\nHost:\r\n\r\n") { await connection.Send(ch.ToString()); testContext.MockSystemClock.UtcNow += ShortDelay; heartbeatManager.OnHeartbeat(testContext.SystemClock.UtcNow); } }); await ReceiveTimeoutResponse(connection, testContext); } }
public async Task RequestTimesOutWhenRequestBodyNotReceivedAtSpecifiedMinimumRate() { var gracePeriod = TimeSpan.FromSeconds(5); var serviceContext = new TestServiceContext(LoggerFactory); var heartbeatManager = new HeartbeatManager(serviceContext.ConnectionManager); var appRunningEvent = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously); using (var server = new TestServer(context => { context.Features.Get <IHttpMinRequestBodyDataRateFeature>().MinDataRate = new MinDataRate(bytesPerSecond: 1, gracePeriod: gracePeriod); // The server must call Request.Body.ReadAsync() *before* the test sets systemClock.UtcNow (which is triggered by the // server calling appRunningEvent.SetResult(null)). If systemClock.UtcNow is set first, it's possible for the test to fail // due to the following race condition: // // 1. [test] systemClock.UtcNow += gracePeriod + TimeSpan.FromSeconds(1); // 2. [server] Heartbeat._timer is triggered, which calls HttpConnection.Tick() // 3. [server] HttpConnection.Tick() calls HttpConnection.CheckForReadDataRateTimeout() // 4. [server] HttpConnection.CheckForReadDataRateTimeout() is a no-op, since _readTimingEnabled is false, // since Request.Body.ReadAsync() has not been called yet // 5. [server] HttpConnection.Tick() sets _lastTimestamp = timestamp // 6. [server] Request.Body.ReadAsync() is called // 6. [test] systemClock.UtcNow is never updated again, so server timestamp is never updated, // so HttpConnection.CheckForReadDataRateTimeout() is always a no-op until test fails // // This is a pretty tight race, since the once-per-second Heartbeat._timer needs to fire between the test updating // systemClock.UtcNow and the server calling Request.Body.ReadAsync(). But it happened often enough to cause // test flakiness in our CI (https://github.com/aspnet/KestrelHttpServer/issues/2539). // // For verification, I was able to induce the race by adding a sleep in the RequestDelegate: // appRunningEvent.SetResult(null); // Thread.Sleep(5000); // return context.Request.Body.ReadAsync(new byte[1], 0, 1); var readTask = context.Request.Body.ReadAsync(new byte[1], 0, 1); appRunningEvent.SetResult(null); return(readTask); }, serviceContext)) { using (var connection = server.CreateConnection()) { await connection.Send( "POST / HTTP/1.1", "Host:", "Content-Length: 1", "", ""); await appRunningEvent.Task.DefaultTimeout(); serviceContext.MockSystemClock.UtcNow += gracePeriod + TimeSpan.FromSeconds(1); heartbeatManager.OnHeartbeat(serviceContext.SystemClock.UtcNow); await connection.Receive( "HTTP/1.1 408 Request Timeout", ""); await connection.ReceiveForcedEnd( "Connection: close", $"Date: {serviceContext.DateHeaderValue}", "Content-Length: 0", "", ""); } } }
public async Task ConnectionClosedEvenIfAppSwallowsException() { var gracePeriod = TimeSpan.FromSeconds(5); var serviceContext = new TestServiceContext(LoggerFactory); var heartbeatManager = new HeartbeatManager(serviceContext.ConnectionManager); var appRunningTcs = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously); var exceptionSwallowedTcs = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously); using (var server = new TestServer(async context => { context.Features.Get <IHttpMinRequestBodyDataRateFeature>().MinDataRate = new MinDataRate(bytesPerSecond: 1, gracePeriod: gracePeriod); // See comment in RequestTimesOutWhenRequestBodyNotReceivedAtSpecifiedMinimumRate for // why we call ReadAsync before setting the appRunningEvent. var readTask = context.Request.Body.ReadAsync(new byte[1], 0, 1); appRunningTcs.SetResult(null); try { await readTask; } catch (BadHttpRequestException ex) when(ex.StatusCode == 408) { exceptionSwallowedTcs.SetResult(null); } catch (Exception ex) { exceptionSwallowedTcs.SetException(ex); } var response = "hello, world"; context.Response.ContentLength = response.Length; await context.Response.WriteAsync("hello, world"); }, serviceContext)) { using (var connection = server.CreateConnection()) { await connection.Send( "POST / HTTP/1.1", "Host:", "Content-Length: 1", "", ""); await appRunningTcs.Task.DefaultTimeout(); serviceContext.MockSystemClock.UtcNow += gracePeriod + TimeSpan.FromSeconds(1); heartbeatManager.OnHeartbeat(serviceContext.SystemClock.UtcNow); await exceptionSwallowedTcs.Task.DefaultTimeout(); await connection.Receive( "HTTP/1.1 200 OK", ""); await connection.ReceiveForcedEnd( $"Date: {serviceContext.DateHeaderValue}", "Content-Length: 12", "", "hello, world"); } } }
// 秒心跳 public static void HeartbeatSecond() { HeartbeatManager.HeartbeatAllPlayerSecond(); }
// 10秒心跳 public static void HeartbeatSecond10() { GameServerLinkManager.HeartbeatSecond10(); HeartbeatManager.HeartbeatAllPlayerSecond10(); }