Skip to content

Commit d19a186

Browse files
committed
Teardown Raven.Embedded.EmbeddedServer as part of stop sequence so that we kill the instance if needed as adhering to cancellation is not possible in host builder root container dispose.
1 parent dd1ca69 commit d19a186

File tree

5 files changed

+60
-7
lines changed

5 files changed

+60
-7
lines changed

src/ServiceControl.Audit.Persistence.RavenDB/IRavenPersistenceLifecycle.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@
66
interface IRavenPersistenceLifecycle
77
{
88
Task Initialize(CancellationToken cancellationToken = default);
9+
Task Stop(CancellationToken cancellationToken);
910
}
1011
}

src/ServiceControl.Audit.Persistence.RavenDB/RavenEmbeddedPersistenceLifecycle.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ public async Task Initialize(CancellationToken cancellationToken = default)
7272
}
7373
}
7474

75+
public Task Stop(CancellationToken cancellationToken) => database!.Stop(cancellationToken);
76+
7577
public void Dispose()
7678
{
7779
documentStore?.Dispose();

src/ServiceControl.Audit.Persistence.RavenDB/RavenExternalPersistenceLifecycle.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ public async Task Initialize(CancellationToken cancellationToken = default)
6464
}
6565
}
6666

67+
public Task Stop(CancellationToken cancellationToken) => Task.CompletedTask; // We are not stopping an external instance
68+
6769
public void Dispose() => documentStore?.Dispose();
6870

6971
IDocumentStore? documentStore;

src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistenceLifecycleHostedService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ sealed class RavenPersistenceLifecycleHostedService(IRavenPersistenceLifecycle l
88
{
99
public Task StartAsync(CancellationToken cancellationToken) => lifecycle.Initialize(cancellationToken);
1010

11-
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
11+
public Task StopAsync(CancellationToken cancellationToken) => lifecycle.Stop(cancellationToken);
1212
}
1313
}

src/ServiceControl.RavenDB/EmbeddedDatabase.cs

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public static EmbeddedDatabase Start(EmbeddedDatabaseConfiguration databaseConfi
5353
var nugetPackagesPath = Path.Combine(databaseConfiguration.DbPath, "Packages", "NuGet");
5454

5555
Logger.InfoFormat("Loading RavenDB license from {0}", licenseFileNameAndServerDirectory.LicenseFileName);
56-
var serverOptions = new ServerOptions
56+
serverOptions = new ServerOptions
5757
{
5858
CommandLineArgs =
5959
[
@@ -162,23 +162,70 @@ public async Task<IDocumentStore> Connect(CancellationToken cancellationToken)
162162

163163
public async Task DeleteDatabase(string dbName)
164164
{
165-
using var store = await EmbeddedServer.Instance.GetDocumentStoreAsync(new DatabaseOptions(dbName) { SkipCreatingDatabase = true });
165+
using var store = await EmbeddedServer.Instance.GetDocumentStoreAsync(new DatabaseOptions(dbName)
166+
{
167+
SkipCreatingDatabase = true
168+
});
166169
await store.Maintenance.Server.SendAsync(new DeleteDatabasesOperation(dbName, true));
167170
}
168171

172+
public async Task Stop(CancellationToken cancellationToken)
173+
{
174+
Logger.Debug("Stopping RavenDB server");
175+
EmbeddedServer.Instance.ServerProcessExited -= OnServerProcessExited;
176+
177+
await shutdownTokenSource.CancelAsync();
178+
179+
// TODO: await EmbeddedServer.Instance.StopAsync(cancellationToken);
180+
181+
var processId = await EmbeddedServer.Instance.GetServerProcessIdAsync(cancellationToken);
182+
183+
var waitForCancellationTask = Task.Delay(Timeout.Infinite, cancellationToken);
184+
var firstTask = await Task.WhenAny(
185+
Task.Run(() => EmbeddedServer.Instance.Dispose(), cancellationToken),
186+
waitForCancellationTask
187+
);
188+
189+
if (firstTask == waitForCancellationTask)
190+
{
191+
try
192+
{
193+
Logger.Warn("Killing RavenDB child process because host cancelled");
194+
var ravenChildProcess = Process.GetProcessById(processId);
195+
ravenChildProcess.Kill(entireProcessTree: true);
196+
}
197+
catch (Exception e)
198+
{
199+
Logger.Error("Killing RavenDB child process failed", e);
200+
}
201+
}
202+
203+
EmbeddedServer.Instance = null!;
204+
Logger.Debug("Stopped RavenDB server");
205+
}
206+
169207
public void Dispose()
170208
{
171209
if (disposed)
172210
{
173211
return;
174212
}
175213

176-
EmbeddedServer.Instance.ServerProcessExited -= OnServerProcessExited;
214+
if (EmbeddedServer.Instance != null)
215+
{
216+
EmbeddedServer.Instance.ServerProcessExited -= OnServerProcessExited;
217+
}
177218

178219
shutdownTokenSource.Cancel();
179-
Logger.Debug("Disposing RavenDB server");
180-
EmbeddedServer.Instance.Dispose();
181-
Logger.Debug("Dispose RavenDB server");
220+
221+
if (EmbeddedServer.Instance != null)
222+
{
223+
serverOptions.GracefulShutdownTimeout = TimeSpan.Zero;
224+
Logger.Debug("Disposing RavenDB server");
225+
EmbeddedServer.Instance.Dispose();
226+
Logger.Debug("Disposed RavenDB server");
227+
}
228+
182229
shutdownTokenSource.Dispose();
183230
applicationStoppingRegistration.Dispose();
184231

@@ -262,6 +309,7 @@ static long DirSize(DirectoryInfo d)
262309
readonly EmbeddedDatabaseConfiguration configuration;
263310
readonly CancellationToken shutdownCancellationToken;
264311
readonly CancellationTokenRegistration applicationStoppingRegistration;
312+
static ServerOptions serverOptions;
265313

266314
static TimeSpan delayBetweenRestarts = TimeSpan.FromSeconds(60);
267315
static readonly ILog Logger = LogManager.GetLogger<EmbeddedDatabase>();

0 commit comments

Comments
 (0)