Implemented more life cycle handling. Added support for rootless environments

This commit is contained in:
2024-12-27 20:08:05 +01:00
parent 039db22207
commit 92e9f42fbc
21 changed files with 738 additions and 20 deletions

View File

@@ -33,6 +33,10 @@ public class ApplicationStateService : IHostedLifecycleService
public Task StoppedAsync(CancellationToken cancellationToken)
=> Task.CompletedTask;
public Task StoppingAsync(CancellationToken cancellationToken)
=> Task.CompletedTask;
public async Task StoppingAsync(CancellationToken cancellationToken)
{
Logger.LogInformation("Stopping services");
await ServerService.Stop();
}
}

View File

@@ -1,9 +1,11 @@
using Docker.DotNet;
using Docker.DotNet.Models;
using MoonCore.Attributes;
using MoonCore.Helpers;
using MoonCore.Models;
using MoonlightServers.Daemon.Helpers;
using MoonlightServers.Daemon.Extensions.ServerExtensions;
using MoonlightServers.Daemon.Models;
using MoonlightServers.Daemon.Models.Cache;
using MoonlightServers.DaemonShared.Enums;
using MoonlightServers.DaemonShared.PanelSide.Http.Responses;
namespace MoonlightServers.Daemon.Services;
@@ -16,6 +18,7 @@ public class ServerService
private readonly RemoteService RemoteService;
private readonly IServiceProvider ServiceProvider;
private bool IsInitialized = false;
private CancellationTokenSource Cancellation = new();
public ServerService(RemoteService remoteService, ILogger<ServerService> logger, IServiceProvider serviceProvider)
{
@@ -68,30 +71,106 @@ public class ServerService
foreach (var configuration in configurations)
await InitializeServer(configuration);
// Attach to docker events
await AttachToDockerEvents();
}
public async Task Stop()
{
Server[] servers;
lock (Servers)
servers = Servers.ToArray();
Logger.LogTrace("Canceling server sub tasks");
foreach (var server in servers)
await server.Cancellation.CancelAsync();
Logger.LogTrace("Canceling own tasks");
await Cancellation.CancelAsync();
}
private async Task AttachToDockerEvents()
{
var dockerClient = ServiceProvider.GetRequiredService<DockerClient>();
Task.Run(async () =>
{
// This lets the event monitor restart
while (!Cancellation.Token.IsCancellationRequested)
{
try
{
Logger.LogTrace("Attached to docker events");
await dockerClient.System.MonitorEventsAsync(new ContainerEventsParameters(),
new Progress<Message>(async message =>
{
if(message.Action != "die")
return;
Server? server;
lock (Servers)
server = Servers.FirstOrDefault(x => x.ContainerId == message.ID);
// TODO: Maybe implement a lookup for containers which id isn't set in the cache
if(server == null)
return;
await server.StateMachine.TransitionTo(ServerState.Offline);
}), Cancellation.Token);
}
catch(TaskCanceledException){} // Can be ignored
catch (Exception e)
{
Logger.LogError("An unhandled error occured while attaching to docker events: {e}", e);
}
}
});
}
private async Task InitializeServer(ServerConfiguration configuration)
{
Logger.LogInformation("Initializing server '{id}'", configuration.Id);
Logger.LogTrace("Initializing server '{id}'", configuration.Id);
var loggerFactory = ServiceProvider.GetRequiredService<ILoggerFactory>();
var server = new Server()
{
Configuration = configuration,
StateMachine = new(ServerState.Offline)
StateMachine = new(ServerState.Offline),
ServiceProvider = ServiceProvider,
Logger = loggerFactory.CreateLogger($"Server {configuration.Id}"),
Console = new(),
Cancellation = new()
};
server.StateMachine.OnError += (state, exception) =>
{
Logger.LogError("Server {id} encountered an unhandled error while transitioning to {state}: {e}",
server.Configuration.Id,
server.Logger.LogError("Encountered an unhandled error while transitioning to {state}: {e}",
state,
exception
);
};
server.StateMachine.OnTransitioned += state =>
{
server.Logger.LogInformation("State: {state}", state);
return Task.CompletedTask;
};
server.StateMachine.AddTransition(ServerState.Offline, ServerState.Starting, ServerState.Offline, async () =>
await ServerActionHelper.Start(server, ServiceProvider)
await server.StateMachineHandler_Start()
);
server.StateMachine.AddTransition(ServerState.Starting, ServerState.Offline);
server.StateMachine.AddTransition(ServerState.Online, ServerState.Offline);
server.StateMachine.AddTransition(ServerState.Stopping, ServerState.Offline);
server.StateMachine.AddTransition(ServerState.Installing, ServerState.Offline);
lock (Servers)
Servers.Add(server);