Finished cleanup of the server system

This commit is contained in:
2025-05-30 22:42:04 +02:00
parent b955bd3527
commit 4fdcc7aff1
3 changed files with 100 additions and 63 deletions

View File

@@ -29,7 +29,7 @@ public class ServersController : Controller
[HttpDelete("{serverId:int}")] [HttpDelete("{serverId:int}")]
public async Task Delete([FromRoute] int serverId) public async Task Delete([FromRoute] int serverId)
{ {
//await ServerService.Delete(serverId); await ServerService.Delete(serverId);
} }
[HttpGet("{serverId:int}/status")] [HttpGet("{serverId:int}/status")]

View File

@@ -21,7 +21,7 @@ public class StorageSubSystem : ServerSubSystem
AppConfiguration = appConfiguration; AppConfiguration = appConfiguration;
} }
public override async Task Initialize() public override Task Initialize()
{ {
Logger.LogDebug("Lazy initializing server file system"); Logger.LogDebug("Lazy initializing server file system");
@@ -42,6 +42,14 @@ public class StorageSubSystem : ServerSubSystem
Logger.LogError("An unhandled error occured while lazy initializing server file system: {e}", e); Logger.LogError("An unhandled error occured while lazy initializing server file system: {e}", e);
} }
}); });
return Task.CompletedTask;
}
public override async Task Delete()
{
await DeleteInstallVolume();
await DeleteRuntimeVolume();
} }
#region Runtime #region Runtime
@@ -65,7 +73,7 @@ public class StorageSubSystem : ServerSubSystem
if (!Directory.Exists(path)) if (!Directory.Exists(path))
Directory.CreateDirectory(path); Directory.CreateDirectory(path);
/*
var consoleSubSystem = Server.GetRequiredSubSystem<ConsoleSubSystem>(); var consoleSubSystem = Server.GetRequiredSubSystem<ConsoleSubSystem>();
await consoleSubSystem.WriteMoonlight("Creating virtual disk file. Please be patient"); await consoleSubSystem.WriteMoonlight("Creating virtual disk file. Please be patient");
@@ -77,7 +85,7 @@ public class StorageSubSystem : ServerSubSystem
await consoleSubSystem.WriteMoonlight("Mounting virtual disk. Please be patient"); await consoleSubSystem.WriteMoonlight("Mounting virtual disk. Please be patient");
await Task.Delay(TimeSpan.FromSeconds(3)); await Task.Delay(TimeSpan.FromSeconds(3));
await consoleSubSystem.WriteMoonlight("Virtual disk ready"); await consoleSubSystem.WriteMoonlight("Virtual disk ready");*/
// TODO: Implement virtual disk // TODO: Implement virtual disk
} }
@@ -95,6 +103,16 @@ public class StorageSubSystem : ServerSubSystem
return Task.FromResult(path); return Task.FromResult(path);
} }
private async Task DeleteRuntimeVolume()
{
var path = await GetRuntimeHostPath();
if(!Directory.Exists(path))
return;
Directory.Delete(path, true);
}
#endregion #endregion
#region Installation #region Installation

View File

@@ -3,6 +3,7 @@ using Docker.DotNet;
using Docker.DotNet.Models; using Docker.DotNet.Models;
using Microsoft.AspNetCore.SignalR; using Microsoft.AspNetCore.SignalR;
using MoonCore.Attributes; using MoonCore.Attributes;
using MoonCore.Exceptions;
using MoonCore.Models; using MoonCore.Models;
using MoonlightServers.Daemon.Extensions; using MoonlightServers.Daemon.Extensions;
using MoonlightServers.Daemon.Http.Hubs; using MoonlightServers.Daemon.Http.Hubs;
@@ -43,16 +44,11 @@ public class ServerService : IHostedLifecycleService
} }
public async Task Sync(int serverId) public async Task Sync(int serverId)
{
if (Servers.TryGetValue(serverId, out var server))
{ {
var serverData = await RemoteService.GetServer(serverId); var serverData = await RemoteService.GetServer(serverId);
var configuration = serverData.ToServerConfiguration(); var configuration = serverData.ToServerConfiguration();
server.Configuration = configuration; await Sync(serverId, configuration);
}
else
await Initialize(serverId);
} }
public async Task Sync(int serverId, ServerConfiguration configuration) public async Task Sync(int serverId, ServerConfiguration configuration)
@@ -126,7 +122,7 @@ public class ServerService : IHostedLifecycleService
{ {
try try
{ {
await Initialize(configuration); await Sync(configuration.Id, configuration);
} }
catch (Exception e) catch (Exception e)
{ {
@@ -173,6 +169,79 @@ public class ServerService : IHostedLifecycleService
Servers[configuration.Id] = server; Servers[configuration.Id] = server;
} }
public async Task Delete(int serverId)
{
var server = Find(serverId);
// If a server with this id doesn't exist we can just exit
if (server == null)
return;
if (server.StateMachine.State == ServerState.Installing)
throw new HttpApiException("Unable to delete a server while it is installing", 400);
if (server.StateMachine.State != ServerState.Offline)
{
// If the server is not offline we need to wait until it goes offline, we
// do that by creating the serverOfflineWaiter task completion source which will get triggered
// when the event handler for state changes gets informed that the server state is now offline
var serverOfflineWaiter = new TaskCompletionSource();
var timeoutCancellation = new CancellationTokenSource();
// Set timeout to 10 seconds, this gives the server 10 seconds to go offline, before the request fails
timeoutCancellation.CancelAfter(TimeSpan.FromSeconds(10));
// Subscribe to state updates in order to get notified when the server is offline
server.StateMachine.OnTransitioned(transition =>
{
// Only listen for changes to offline
if (transition.Destination != ServerState.Offline)
return;
// If the timeout has already been reached, ignore all changes
if (timeoutCancellation.IsCancellationRequested)
return;
// Server is finally offline, notify the request that we now can delete the server
serverOfflineWaiter.SetResult();
});
// Now we trigger the kill and waiting for the server to be deleted
await server.StateMachine.FireAsync(ServerTrigger.Kill);
try
{
await serverOfflineWaiter.Task.WaitAsync(timeoutCancellation.Token);
await DeleteServer_Unhandled(server);
}
catch (TaskCanceledException)
{
Logger.LogWarning(
"Deletion of server {id} failed because it didnt stop in time despite being killed",
server.Configuration.Id
);
throw new HttpApiException(
"Could not kill the server in time for the deletion. Please try again later",
500
);
}
}
else
await DeleteServer_Unhandled(server);
}
private async Task DeleteServer_Unhandled(Server server)
{
await server.DisposeAsync();
await server.Delete();
lock (Servers)
Servers.Remove(server.Configuration.Id);
}
#region Docker Monitoring #region Docker Monitoring
private async Task MonitorContainers() private async Task MonitorContainers()
@@ -283,55 +352,5 @@ public class ServerService : IHostedLifecycleService
}); });
* *
* *
*public async Task Delete(int serverId)
{
var server = GetServer(serverId);
// If a server with this id doesn't exist we can just exit
if (server == null)
return;
if (server.State == ServerState.Installing)
throw new HttpApiException("Unable to delete a server while it is installing", 400);
#region Callbacks
var deleteCompletion = new TaskCompletionSource();
async Task HandleStateChange(ServerState state)
{
if (state == ServerState.Offline)
await DeleteServer();
}
async Task DeleteServer()
{
await server.CancelTasks();
await server.DestroyStorage();
await server.RemoveInstallationVolume();
await server.RemoveRuntimeVolume();
deleteCompletion.SetResult();
lock (Servers)
Servers.Remove(server);
}
#endregion
// If the server is still online, we are killing it and then
// waiting for the callback to trigger notifying us that the server is now offline
// so we can delete it. The request will pause until then using the deleteCompletion task
if (server.State != ServerState.Offline)
{
server.OnStateChanged += HandleStateChange;
await server.Kill();
await deleteCompletion.Task;
}
else
await DeleteServer();
}
*
*/ */
} }