diff --git a/ExtractorUtils.Test/unit/Unstable/RuntimeTest.cs b/ExtractorUtils.Test/unit/Unstable/RuntimeTest.cs index 50d9a03e..48efaa54 100644 --- a/ExtractorUtils.Test/unit/Unstable/RuntimeTest.cs +++ b/ExtractorUtils.Test/unit/Unstable/RuntimeTest.cs @@ -180,6 +180,9 @@ private ExtractorRuntimeBuilder CreateMockRuntimeBu builder.ExternalServices = services; builder.AddLogger = false; + // Reduce backoff times for faster tests + builder.BackoffBase = 50; + return builder; } @@ -187,6 +190,9 @@ private ExtractorRuntimeBuilder CreateMockRuntimeBu public async Task TestRuntimeRestartNewConfig() { var builder = CreateMockRuntimeBuilder(); + // Restart policy won't be the default "Always" in customer envs, but we should + // still restart on config change. + builder.RestartPolicy = ExtractorRestartPolicy.OnError; using var evt = new ManualResetEventSlim(false); diff --git a/ExtractorUtils/Unstable/Runtime/Runtime.cs b/ExtractorUtils/Unstable/Runtime/Runtime.cs index 8928b9da..f72527be 100644 --- a/ExtractorUtils/Unstable/Runtime/Runtime.cs +++ b/ExtractorUtils/Unstable/Runtime/Runtime.cs @@ -36,6 +36,11 @@ enum ExtractorRunResult /// The extractor crashed. /// Error, + /// + /// The extractor was stopped with a clean shutdown. + /// But we need to restart it (possibly due to a revision change). + /// + RestartRequired } /// @@ -138,6 +143,7 @@ public async Task Run() } else if (result == ExtractorRunResult.CleanShutdown) { + _activeLogger.LogInformation("Extractor stopped cleanly with policy {Policy}", _params.RestartPolicy); // Shut down, if the extractor is configured to only restart on error. if (_params.RestartPolicy != ExtractorRestartPolicy.Always) { @@ -147,6 +153,11 @@ public async Task Run() // Otherwise, immediately restart. backoff = 0; } + else if (result == ExtractorRunResult.RestartRequired) + { + _activeLogger.LogInformation("Extractor stopped cleanly with restart required, restarting with backoff"); + backoff = 1; + } if (backoff == 0) { @@ -328,6 +339,7 @@ private async Task BuildAndRunExtractor(ServiceProvider prov { using var internalTokenSource = CancellationTokenSource.CreateLinkedTokenSource(_source.Token); TExtractor extractor; + var shouldRestart = false; try { if (_params.AddMetrics) @@ -386,6 +398,7 @@ private async Task BuildAndRunExtractor(ServiceProvider prov { _activeLogger.LogInformation("Revision changed, reloading config"); internalTokenSource.Cancel(); + shouldRestart = true; await extractorTask.ConfigureAwait(false); } @@ -394,6 +407,7 @@ private async Task BuildAndRunExtractor(ServiceProvider prov { ExceptionDispatchInfo.Capture(extractorTask.Exception).Throw(); } + } catch (OperationCanceledException) when (internalTokenSource.IsCancellationRequested) { @@ -415,7 +429,11 @@ private async Task BuildAndRunExtractor(ServiceProvider prov return ExtractorRunResult.Error; } - + if (shouldRestart) + { + _activeLogger.LogInformation("Extractor stopped cleanly with policy {Policy}, restart is required", _params.RestartPolicy); + return ExtractorRunResult.RestartRequired; + } return ExtractorRunResult.CleanShutdown; }