fixed server_stopped file check

This commit is contained in:
Frank Harris 2026-06-10 18:37:40 -04:00
parent a1f1f8529f
commit 1d04e2a4e8
2 changed files with 32 additions and 48 deletions

View file

@ -502,7 +502,7 @@ sub create_screen_cmd
sub create_screen_cmd_loop sub create_screen_cmd_loop
{ {
my ($screen_id, $exec_cmd, $priority, $affinity, $envVars) = @_; my ($screen_id, $exec_cmd, $priority, $affinity, $envVars, $status_hint_file) = @_;
my $server_start_batfile = "_serverStart.bat"; my $server_start_batfile = "_serverStart.bat";
$exec_cmd = replace_OGP_Env_Vars($screen_id, "", "", $exec_cmd); $exec_cmd = replace_OGP_Env_Vars($screen_id, "", "", $exec_cmd);
@ -517,6 +517,7 @@ sub create_screen_cmd_loop
if(defined $envVars && $envVars ne ""){ if(defined $envVars && $envVars ne ""){
$batch_server_command .= $envVars; $batch_server_command .= $envVars;
}# lines 500-515, inside sub create_screen_cmd_loop }# lines 500-515, inside sub create_screen_cmd_loop
$status_hint_file = "" unless(defined($status_hint_file));
$batch_server_command .= "set STARTTIME=%TIME: =0%" . "\r\n" $batch_server_command .= "set STARTTIME=%TIME: =0%" . "\r\n"
. "\@echo off\r\n" . "\@echo off\r\n"
. "if exist \"_alsoRun.bat\" call \"_alsoRun.bat\"\r\n" . "if exist \"_alsoRun.bat\" call \"_alsoRun.bat\"\r\n"
@ -529,7 +530,7 @@ $batch_server_command .= "set STARTTIME=%TIME: =0%" . "\r\n"
. "set hour=%hh:~1%\r\n" . "set hour=%hh:~1%\r\n"
. "set minute=%mm:~1%\r\n" . "set minute=%mm:~1%\r\n"
. "set second=%ss:~1%\r\n" . "set second=%ss:~1%\r\n"
. "if exist SERVER_STOPPED exit\r\n" . "if exist \"$status_hint_file\" findstr /I /R /C:\"^[0-9][0-9]*,STOPPING$\" /C:\"^[0-9][0-9]*,STOPPED$\" \"$status_hint_file\" >nul && exit\r\n"
. "IF \"%hour%\" == \"00\" IF \"%minute%\" == \"00\" IF %second% lss 60 exit\r\n" . "IF \"%hour%\" == \"00\" IF \"%minute%\" == \"00\" IF %second% lss 60 exit\r\n"
. "timeout /t 30 /nobreak >nul\r\n" . "timeout /t 30 /nobreak >nul\r\n"
. "goto TOP\r\n"; . "goto TOP\r\n";
@ -1052,9 +1053,8 @@ sub server_status_without_decrypt
if(!$process_running && ((!PORT_VALIDATION_ENABLED && $game_port_listening) || ($expected_count > 0 && $listening_count > 0))) if(!$process_running && ((!PORT_VALIDATION_ENABLED && $game_port_listening) || ($expected_count > 0 && $listening_count > 0)))
{ {
$status = "ONLINE"; $status = "WARNING";
$ready = 1; $status_state = "Warning";
$status_state = $missing_count == 0 ? "Running" : "Warning";
$last_error = "Required port is listening but the managed screen session is not running."; $last_error = "Required port is listening but the managed screen session is not running.";
} }
elsif($process_running) elsif($process_running)
@ -1081,7 +1081,7 @@ sub server_status_without_decrypt
elsif($effective_hint eq "STOPPING") elsif($effective_hint eq "STOPPING")
{ {
$status = "STOPPING"; $status = "STOPPING";
$status_state = "Starting"; $status_state = "Stopping";
} }
elsif($hint_timestamp > 0 && (time() - $hint_timestamp) > $startup_timeout) elsif($hint_timestamp > 0 && (time() - $hint_timestamp) > $startup_timeout)
{ {
@ -1127,6 +1127,7 @@ sub server_status_without_decrypt
pid => $game_pid ne "" ? $game_pid : ($windows_pid ne "" ? $windows_pid : $screen_pid), pid => $game_pid ne "" ? $game_pid : ($windows_pid ne "" ? $windows_pid : $screen_pid),
screen_pid => $screen_pid, screen_pid => $screen_pid,
windows_pid => $windows_pid, windows_pid => $windows_pid,
linux_pid => "",
session_name => $screen_id, session_name => $screen_id,
ip => $server_ip, ip => $server_ip,
port => $server_port, port => $server_port,
@ -1137,17 +1138,6 @@ sub server_status_without_decrypt
}; };
} }
# Delete Server Stopped Status File:
sub deleteStoppedStatFile
{
my ($home_path) = @_;
my $server_stop_status_file = Path::Class::File->new($home_path, "SERVER_STOPPED");
if(-e $server_stop_status_file)
{
unlink $server_stop_status_file;
}
}
# Universal startup function # Universal startup function
sub universal_start sub universal_start
{ {
@ -1223,6 +1213,9 @@ sub universal_start_without_decrypt
} }
my $screen_id = create_screen_id(SCREEN_TYPE_HOME, $home_id); my $screen_id = create_screen_id(SCREEN_TYPE_HOME, $home_id);
my $status_hint_file = get_status_hint_path($home_id);
my $status_hint_file_windows = clean(`cygpath -wa $status_hint_file`);
chomp($status_hint_file_windows);
# Replace any OGP variables # Replace any OGP variables
$startup_cmd = replace_OGP_Env_Vars($screen_id, $home_id, $home_path, $startup_cmd, $game_key); $startup_cmd = replace_OGP_Env_Vars($screen_id, $home_id, $home_path, $startup_cmd, $game_key);
@ -1288,8 +1281,7 @@ sub universal_start_without_decrypt
if($file_extension eq ".jar") if($file_extension eq ".jar")
{ {
if(defined($Cfg::Preferences{ogp_autorestart_server}) && $Cfg::Preferences{ogp_autorestart_server} eq "1"){ if(defined($Cfg::Preferences{ogp_autorestart_server}) && $Cfg::Preferences{ogp_autorestart_server} eq "1"){
deleteStoppedStatFile($home_path); $cli_bin = create_screen_cmd_loop($screen_id, "$startup_cmd", $priority, $affinity, undef, $status_hint_file_windows);
$cli_bin = create_screen_cmd_loop($screen_id, "$startup_cmd", $priority, $affinity);
}else{ }else{
$cli_bin = create_screen_cmd($screen_id, "cmd /Q /C start $priority $affinity /WAIT $startup_cmd"); $cli_bin = create_screen_cmd($screen_id, "cmd /Q /C start $priority $affinity /WAIT $startup_cmd");
} }
@ -1300,8 +1292,7 @@ sub universal_start_without_decrypt
# but it can be a good way to improve the server startup. To be able to use # but it can be a good way to improve the server startup. To be able to use
# sh/bash scripts as server executable I added this piece to the agent: # sh/bash scripts as server executable I added this piece to the agent:
if(defined($Cfg::Preferences{ogp_autorestart_server}) && $Cfg::Preferences{ogp_autorestart_server} eq "1"){ if(defined($Cfg::Preferences{ogp_autorestart_server}) && $Cfg::Preferences{ogp_autorestart_server} eq "1"){
deleteStoppedStatFile($home_path); $cli_bin = create_screen_cmd_loop($screen_id, "bash $game_binary_dir/$server_exe $startup_cmd", $priority, $affinity, undef, $status_hint_file_windows);
$cli_bin = create_screen_cmd_loop($screen_id, "bash $game_binary_dir/$server_exe $startup_cmd", $priority, $affinity);
}else{ }else{
$cli_bin = create_screen_cmd($screen_id, "cmd /Q /C start $priority $affinity /WAIT bash $game_binary_dir/$server_exe $startup_cmd"); $cli_bin = create_screen_cmd($screen_id, "cmd /Q /C start $priority $affinity /WAIT bash $game_binary_dir/$server_exe $startup_cmd");
} }
@ -1309,8 +1300,7 @@ sub universal_start_without_decrypt
else else
{ {
if(defined($Cfg::Preferences{ogp_autorestart_server}) && $Cfg::Preferences{ogp_autorestart_server} eq "1"){ if(defined($Cfg::Preferences{ogp_autorestart_server}) && $Cfg::Preferences{ogp_autorestart_server} eq "1"){
deleteStoppedStatFile($home_path); $cli_bin = create_screen_cmd_loop($screen_id, "$win_game_binary_dir\\$server_exe $startup_cmd", $priority, $affinity, undef, $status_hint_file_windows);
$cli_bin = create_screen_cmd_loop($screen_id, "$win_game_binary_dir\\$server_exe $startup_cmd", $priority, $affinity);
}else{ }else{
# Below lines should only be used for launching non-auto restart game servers # Below lines should only be used for launching non-auto restart game servers
$win_game_binary_dir =~ s/\\/\\\\/g; $win_game_binary_dir =~ s/\\/\\\\/g;
@ -1634,21 +1624,6 @@ sub stop_server_without_decrypt
or logger "Cannot remove the startup flag file $startup_file $!"; or logger "Cannot remove the startup flag file $startup_file $!";
} }
# Create file indicator that the game server has been stopped if defined
if(defined($Cfg::Preferences{ogp_autorestart_server}) && $Cfg::Preferences{ogp_autorestart_server} eq "1"){
# Get current directory and chdir into the game's home dir
my $curDir = getcwd();
chdir $home_path;
# Create stopped indicator file used by autorestart of OGP if server crashes
open(STOPFILE, '>', "SERVER_STOPPED");
close(STOPFILE);
# Return to original directory
chdir $curDir;
}
my $screen_id = create_screen_id(SCREEN_TYPE_HOME, $home_id); my $screen_id = create_screen_id(SCREEN_TYPE_HOME, $home_id);
my $screen_pid = get_screen_pid_without_decrypt($home_id); my $screen_pid = get_screen_pid_without_decrypt($home_id);
my $pid_meta = read_pid_metadata($home_id); my $pid_meta = read_pid_metadata($home_id);
@ -1675,15 +1650,16 @@ sub stop_server_without_decrypt
system("cmd /C taskkill /F /T /PID $port_pid >nul 2>&1"); system("cmd /C taskkill /F /T /PID $port_pid >nul 2>&1");
} }
my $stop_result = verify_server_stopped_without_decrypt($home_id, $server_ip, $server_port); my $stop_result = verify_runtime_stop_complete_without_decrypt($home_id, $server_ip, $server_port);
if($stop_result == 0) if($stop_result == 0)
{ {
clear_pid_metadata($home_id); clear_pid_metadata($home_id);
write_status_hint($home_id, "STOPPED");
} }
return $stop_result; return $stop_result;
} }
sub verify_server_stopped_without_decrypt sub verify_runtime_stop_complete_without_decrypt
{ {
my ($home_id, $server_ip, $server_port) = @_; my ($home_id, $server_ip, $server_port) = @_;
my $pid_meta = read_pid_metadata($home_id); my $pid_meta = read_pid_metadata($home_id);
@ -1694,7 +1670,11 @@ sub verify_server_stopped_without_decrypt
$pid_running = 1 if(defined($pid_meta->{windows_pid}) && $pid_meta->{windows_pid} =~ /^\d+$/ && is_pid_alive_without_decrypt($pid_meta->{windows_pid}) == 1); $pid_running = 1 if(defined($pid_meta->{windows_pid}) && $pid_meta->{windows_pid} =~ /^\d+$/ && is_pid_alive_without_decrypt($pid_meta->{windows_pid}) == 1);
$pid_running = 1 if(!$pid_running && defined($pid_meta->{game_pid}) && $pid_meta->{game_pid} =~ /^\d+$/ && is_pid_alive_without_decrypt($pid_meta->{game_pid}) == 1); $pid_running = 1 if(!$pid_running && defined($pid_meta->{game_pid}) && $pid_meta->{game_pid} =~ /^\d+$/ && is_pid_alive_without_decrypt($pid_meta->{game_pid}) == 1);
my $port_listening = is_port_listening_without_decrypt($server_ip, $server_port); my $port_listening = is_port_listening_without_decrypt($server_ip, $server_port);
return 0 if(!$session_running && !$pid_running && !$port_listening); if(!$session_running && !$pid_running && !$port_listening)
{
write_status_hint($home_id, "STOPPED");
return 0;
}
sleep 2; sleep 2;
} }
my $screen_id = create_screen_id(SCREEN_TYPE_HOME, $home_id); my $screen_id = create_screen_id(SCREEN_TYPE_HOME, $home_id);
@ -1713,6 +1693,7 @@ sub verify_server_stopped_without_decrypt
logger "Server $server_ip:$server_port is still running or listening after stop escalation."; logger "Server $server_ip:$server_port is still running or listening after stop escalation.";
return 1; return 1;
} }
write_status_hint($home_id, "STOPPED");
return 0; return 0;
} }
@ -3001,7 +2982,7 @@ sub restart_server_without_decrypt
{ {
logger "Waiting 60 seconds before starting the server again."; logger "Waiting 60 seconds before starting the server again.";
sleep 60; sleep 60;
if (verify_server_stopped_without_decrypt($home_id, $server_ip, $server_port) != 0) if (verify_runtime_stop_complete_without_decrypt($home_id, $server_ip, $server_port) != 0)
{ {
logger "Restart cancelled: previous instance is still active after stop wait window."; logger "Restart cancelled: previous instance is still active after stop wait window.";
return -2; return -2;

View file

@ -48,12 +48,15 @@ Tracked fields include PID/session information used to stop the right process re
When stop is requested, the agent now: When stop is requested, the agent now:
1. marks status hint as `STOPPING` 1. marks status hint as `STOPPING`
2. creates `SERVER_STOPPED` marker for autorestart handling 2. removes startup flag for `<ip>-<port>`
3. removes startup flag for `<ip>-<port>` 3. kills tracked PIDs (`screen_pid`, `windows_pid`, `game_pid`) if present
4. kills tracked PIDs (`screen_pid`, `windows_pid`, `game_pid`) if present 4. kills managed screen session
5. kills managed screen session 5. checks if the game port is still listening and kills the owning PID
6. checks if the game port is still listening and kills the owning PID 6. verifies stop success (no managed session, no tracked running PID, no listening game port)
7. verifies stop success (no managed session, no tracked running PID, no listening game port) 7. writes status hint `STOPPED` only after verification passes
The agent no longer creates or reads `SERVER_STOPPED`/`Server_Stopped` marker files for lifecycle control.
Autorestart loop control now uses agent-owned runtime status hints (`STARTING`/`STOPPING`/`STOPPED`) instead of game-home marker files.
## Restart behavior ## Restart behavior