feat(shutdown): passive drain and rename DisableSoftCrash

Shutdown now proceeds in three phases: close listeners immediately on
signal, broadcast the in-game countdown, wait up to ShutdownDrainSeconds
(default 30) for sessions to disconnect naturally via DrainPassive, then
force-close any stragglers. This prevents players from entering new
quests after the countdown starts, and lets mid-quest sessions finish
saving without being killed mid-write. A second SIGINT during passive
drain cancels it so the force-close phase runs immediately.

Renamed DisableSoftCrash -> DisableShutdownCountdown since the flag
controls the countdown, not crash behaviour. Existing config.json files
keep working via a Viper alias on the legacy key.

Closes #179.
This commit is contained in:
Houmgaor
2026-04-06 19:32:35 +02:00
parent 9b0f735335
commit e48d33ca76
7 changed files with 134 additions and 64 deletions

View File

@@ -149,26 +149,26 @@ func TestGetOutboundIP4(t *testing.T) {
// TestConfigStructTypes verifies Config struct fields have correct types
func TestConfigStructTypes(t *testing.T) {
cfg := &Config{
Host: "localhost",
BinPath: "/path/to/bin",
Language: "en",
DisableSoftCrash: false,
HideLoginNotice: false,
LoginNotices: []string{"Notice"},
PatchServerManifest: "http://patch.example.com",
PatchServerFile: "http://files.example.com",
Host: "localhost",
BinPath: "/path/to/bin",
Language: "en",
DisableShutdownCountdown: false,
HideLoginNotice: false,
LoginNotices: []string{"Notice"},
PatchServerManifest: "http://patch.example.com",
PatchServerFile: "http://files.example.com",
DeleteOnSaveCorruption: false,
DisableSaveIntegrityCheck: false,
ClientMode: "ZZ",
RealClientMode: ZZ,
QuestCacheExpiry: 3600,
CommandPrefix: "!",
AutoCreateAccount: false,
LoopDelay: 100,
DefaultCourses: []uint16{1, 2, 3},
EarthStatus: 1,
EarthID: 1,
EarthMonsters: []int32{1, 2, 3},
ClientMode: "ZZ",
RealClientMode: ZZ,
QuestCacheExpiry: 3600,
CommandPrefix: "!",
AutoCreateAccount: false,
LoopDelay: 100,
DefaultCourses: []uint16{1, 2, 3},
EarthStatus: 1,
EarthID: 1,
EarthMonsters: []int32{1, 2, 3},
SaveDumps: SaveDumpOptions{
Enabled: true,
RawEnabled: false,