Enhance school management and protocol handling by introducing a new worker failure mechanism, ensuring proper cleanup of schools when a worker thread encounters an error. Update the map snapshot protocol to allow larger school data sizes, improving the handling of extensive map layouts. Revise documentation to reflect changes in save intervals and introduce a minimum save interval for better performance. Update tests to validate the new functionalities and ensure robustness in handling large data scenarios.
This commit is contained in:
@@ -144,9 +144,39 @@ internal sealed class GameLoopService(
|
||||
case GameCommand.ReloadSaves reload:
|
||||
await HandleReloadAsync(reload).ConfigureAwait(false);
|
||||
break;
|
||||
|
||||
case GameCommand.WorkerFailed failed:
|
||||
HandleWorkerFailed(failed.SchoolId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A school's thread died. Drop it from the table so the menu stops drawing a card whose clock
|
||||
/// never moves again, and tell anybody watching it to go back to the menu. The save file stays
|
||||
/// where it is — a restart or <c>reload-schools</c> is the way back.
|
||||
/// </summary>
|
||||
private void HandleWorkerFailed(int schoolId)
|
||||
{
|
||||
if (!_workers.ContainsKey(schoolId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Untrack(schoolId);
|
||||
|
||||
foreach (var client in clients.All)
|
||||
{
|
||||
if (client.OpenSchoolId == schoolId)
|
||||
{
|
||||
client.OpenSchoolId = null;
|
||||
SendSchoolGone(client, schoolId);
|
||||
}
|
||||
}
|
||||
|
||||
logger.LogError("School {SchoolId} stopped after a worker failure; its save file is unchanged.", schoolId);
|
||||
}
|
||||
|
||||
private async Task HandleCreateAsync(GameCommand.CreateSchool command)
|
||||
{
|
||||
try
|
||||
@@ -373,6 +403,11 @@ internal sealed class GameLoopService(
|
||||
await worker.StopAsync(persist: false).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (_workers.Count > 0)
|
||||
{
|
||||
logger.LogInformation("Restored {Count} school(s) from disk.", _workers.Count);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task StopAllWorkersAsync(bool persist)
|
||||
@@ -386,11 +421,6 @@ internal sealed class GameLoopService(
|
||||
{
|
||||
await Task.WhenAll(stopping).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (_workers.Count > 0)
|
||||
{
|
||||
logger.LogInformation("Restored {Count} school(s) from disk.", _workers.Count);
|
||||
}
|
||||
}
|
||||
|
||||
private SchoolWorker SpawnWorker(
|
||||
@@ -416,6 +446,7 @@ internal sealed class GameLoopService(
|
||||
metrics,
|
||||
store,
|
||||
mods,
|
||||
onFailed: schoolId => commands.Enqueue(new GameCommand.WorkerFailed(schoolId)),
|
||||
loggerFactory.CreateLogger($"HSchool.Server.Game.SchoolWorker.{id}"));
|
||||
|
||||
private void Track(SchoolWorker worker)
|
||||
|
||||
Reference in New Issue
Block a user