Skip to content

Commit 7482a6d

Browse files
committed
Dispose Process instance using var, ensure EmbeddedServer.Instance.Dispose always gets invoked, added comment and improved code readability
1 parent 974a96a commit 7482a6d

File tree

1 file changed

+21
-10
lines changed

1 file changed

+21
-10
lines changed

src/ServiceControl.RavenDB/EmbeddedDatabase.cs

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@ public static EmbeddedDatabase Start(EmbeddedDatabaseConfiguration databaseConfi
6666
Logger.InfoFormat("Loading RavenDB license from {0}", licenseFileNameAndServerDirectory.LicenseFileName);
6767
var serverOptions = new ServerOptions
6868
{
69-
GracefulShutdownTimeout = TimeSpan.FromHours(1), // During Stop/Dispose we manually control this
7069
CommandLineArgs =
7170
[
7271
$"--Logs.Mode={databaseConfiguration.LogsMode}",
@@ -189,30 +188,42 @@ public async Task Stop(CancellationToken cancellationToken)
189188

190189
await shutdownTokenSource.CancelAsync();
191190

192-
// TODO: await EmbeddedServer.Instance.StopAsync(cancellationToken);
191+
// EmbeddedServer does not have have an async Stop method, the Dispose operation blocks and waits
192+
// until its GracefulShutdownTimeout is reached and then does a Process.Kill
193+
//
194+
// This logic gets the child process ID uses a Task.Delay with infinite.
195+
//
196+
// a. The Task.Delay gets cancelled first
197+
// b. The EmbeddedServer.Dispose completes first
198+
//
199+
// If the Task.Delay gets cancelled first this means Dispose is still running and
200+
// then we kill the process
201+
202+
serverOptions!.GracefulShutdownTimeout = TimeSpan.FromHours(1); // During Stop/Dispose we manually control this
193203

194204
var processId = await EmbeddedServer.Instance.GetServerProcessIdAsync(cancellationToken);
195205

206+
// Dispose always need to be invoked, even when already cancelled
207+
var disposeTask = Task.Run(() => EmbeddedServer.Instance.Dispose(), CancellationToken.None);
208+
196209
var waitForCancellationTask = Task.Delay(Timeout.Infinite, cancellationToken);
197-
var firstTask = await Task.WhenAny(
198-
Task.Run(() => EmbeddedServer.Instance.Dispose(), cancellationToken),
199-
waitForCancellationTask
200-
);
201210

202-
if (firstTask == waitForCancellationTask)
211+
var delayIsCancelled = waitForCancellationTask == await Task.WhenAny(disposeTask, waitForCancellationTask);
212+
213+
if (delayIsCancelled)
203214
{
204215
try
205216
{
206-
Logger.WarnFormat("Killing RavenDB server PID {0} child process because host cancelled", processId);
207-
var ravenChildProcess = Process.GetProcessById(processId);
217+
Logger.WarnFormat("Killing RavenDB server PID {0} because host cancelled", processId);
218+
using var ravenChildProcess = Process.GetProcessById(processId);
208219
ravenChildProcess.Kill(entireProcessTree: true);
209220
// Kill only signals
210221
Logger.WarnFormat("Waiting for RavenDB server PID {0} to exit... ", processId);
211222
await ravenChildProcess.WaitForExitAsync(CancellationToken.None);
212223
}
213224
catch (Exception e)
214225
{
215-
Logger.ErrorFormat("Failed to kill RavenDB server PID {0}\n{1}", processId, e);
226+
Logger.ErrorFormat("Failed to kill RavenDB server PID {0} shutdown\n{1}", processId, e);
216227
}
217228
}
218229

0 commit comments

Comments
 (0)