1
0
mirror of https://github.com/chylex/Minecraft-Phantom-Panel.git synced 2025-05-08 12:34:03 +02:00

Change online player check in backup scheduler to wait for any server process output before retrying

This commit is contained in:
chylex 2023-02-06 23:17:18 +01:00
parent b3104f9ac3
commit 09e7510358
Signed by: chylex
GPG Key ID: 4DE42C8F19A80548
3 changed files with 63 additions and 19 deletions
Agent/Phantom.Agent.Services/Backups
Utils/Phantom.Utils.Runtime

View File

@ -55,7 +55,7 @@ sealed partial class BackupManager {
public async Task<BackupCreationResult> CreateBackup() {
logger.Information("Backup started.");
session.AddOutputListener(listener.OnOutput, 0);
session.AddOutputListener(listener.OnOutput, maxLinesToReadFromHistory: 0);
try {
var resultBuilder = new BackupCreationResult.Builder();

View File

@ -11,13 +11,13 @@ sealed class BackupScheduler : CancellableBackgroundTask {
private static readonly TimeSpan InitialDelay = TimeSpan.FromMinutes(2);
private static readonly TimeSpan BackupInterval = TimeSpan.FromMinutes(30);
private static readonly TimeSpan BackupFailureRetryDelay = TimeSpan.FromMinutes(5);
private static readonly TimeSpan OnlinePlayersCheckInterval = TimeSpan.FromMinutes(1);
private readonly string loggerName;
private readonly BackupManager backupManager;
private readonly InstanceSession session;
private readonly int serverPort;
private readonly ServerStatusProtocol serverStatusProtocol;
private readonly ManualResetEventSlim serverOutputWhileWaitingForOnlinePlayers = new ();
public BackupScheduler(TaskManager taskManager, BackupManager backupManager, InstanceSession session, int serverPort, string loggerName) : base(PhantomLogger.Create<BackupScheduler>(loggerName), taskManager, "Backup scheduler for " + loggerName) {
this.loggerName = loggerName;
@ -52,24 +52,41 @@ sealed class BackupScheduler : CancellableBackgroundTask {
private async Task WaitForOnlinePlayers() {
bool needsToLogOfflinePlayersMessage = true;
while (!CancellationToken.IsCancellationRequested) {
var onlinePlayerCount = await serverStatusProtocol.GetOnlinePlayerCount(serverPort, CancellationToken);
if (onlinePlayerCount == null) {
Logger.Warning("Could not detect whether any players are online, starting a new backup.");
break;
}
if (onlinePlayerCount > 0) {
Logger.Information("Players are online, starting a new backup.");
break;
}
if (needsToLogOfflinePlayersMessage) {
needsToLogOfflinePlayersMessage = false;
Logger.Information("No players are online, waiting for someone to join before starting a new backup.");
}
session.AddOutputListener(ServerOutputListener, maxLinesToReadFromHistory: 0);
try {
while (!CancellationToken.IsCancellationRequested) {
serverOutputWhileWaitingForOnlinePlayers.Reset();
var onlinePlayerCount = await serverStatusProtocol.GetOnlinePlayerCount(serverPort, CancellationToken);
if (onlinePlayerCount == null) {
Logger.Warning("Could not detect whether any players are online, starting a new backup.");
break;
}
await Task.Delay(OnlinePlayersCheckInterval, CancellationToken);
if (onlinePlayerCount > 0) {
Logger.Information("Players are online, starting a new backup.");
break;
}
if (needsToLogOfflinePlayersMessage) {
needsToLogOfflinePlayersMessage = false;
Logger.Information("No players are online, waiting for someone to join before starting a new backup.");
}
await Task.Delay(TimeSpan.FromSeconds(10), CancellationToken);
Logger.Verbose("Waiting for server output before checking for online players again...");
await serverOutputWhileWaitingForOnlinePlayers.WaitHandle.WaitOneAsync(CancellationToken);
}
} finally {
session.RemoveOutputListener(ServerOutputListener);
}
}
private void ServerOutputListener(object? sender, string line) {
if (!serverOutputWhileWaitingForOnlinePlayers.IsSet) {
serverOutputWhileWaitingForOnlinePlayers.Set();
Logger.Verbose("Detected server output, signalling to check for online players again.");
}
}
}

View File

@ -0,0 +1,27 @@
namespace Phantom.Utils.Runtime;
public static class WaitHandleExtensions {
public static Task WaitOneAsync(this WaitHandle waitHandle, CancellationToken cancellationToken = default) {
var taskCompletionSource = new TaskCompletionSource();
void SetResult(object? state, bool timedOut) {
taskCompletionSource.TrySetResult();
}
void SetCancelled() {
taskCompletionSource.TrySetCanceled(cancellationToken);
}
var waitRegistration = ThreadPool.RegisterWaitForSingleObject(waitHandle, SetResult, null, Timeout.InfiniteTimeSpan, true);
var tokenRegistration = cancellationToken.Register(SetCancelled, useSynchronizationContext: false);
void Cleanup(Task t) {
waitRegistration.Unregister(null);
tokenRegistration.Dispose();
}
var task = taskCompletionSource.Task;
task.ContinueWith(Cleanup, CancellationToken.None);
return task;
}
}