Implemented more life cycle handling. Added support for rootless environments
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user