Skip to content

Commit d4092af

Browse files
committed
Harden Factorio quit wait against hangs
1 parent c850bd8 commit d4092af

1 file changed

Lines changed: 40 additions & 0 deletions

File tree

fact/util.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"strings"
1414
"sync"
1515
"sync/atomic"
16+
"syscall"
1617
"time"
1718

1819
"github.com/bwmarrin/discordgo"
@@ -1274,12 +1275,51 @@ func FactWhisper(player, format string, args ...interface{}) {
12741275
}
12751276

12761277
func WaitFactQuit(waiting bool) {
1278+
checkProcessAlive := func() bool {
1279+
cmd := glob.FactorioCmd
1280+
if cmd == nil || cmd.Process == nil {
1281+
return false
1282+
}
1283+
if cmd.ProcessState != nil && cmd.ProcessState.Exited() {
1284+
return false
1285+
}
1286+
if err := cmd.Process.Signal(syscall.Signal(0)); err != nil {
1287+
return false
1288+
}
1289+
// When cmd.Wait() hasn't been called yet, an exited child can remain as a zombie
1290+
// and still answer signal 0 successfully. Treat zombies as not alive.
1291+
if data, err := os.ReadFile(fmt.Sprintf("/proc/%d/stat", cmd.Process.Pid)); err == nil {
1292+
if s := string(data); s != "" {
1293+
if idx := strings.LastIndex(s, ") "); idx >= 0 && len(s) > idx+2 && s[idx+2] == 'Z' {
1294+
return false
1295+
}
1296+
}
1297+
}
1298+
return true
1299+
}
1300+
12771301
if waiting {
1302+
started := time.Now()
12781303
for FactIsRunning && FactorioBooted && glob.ServerRunning {
1304+
// "Goodbye" log parsing normally clears FactIsRunning. If that line is missed,
1305+
// fall back to the actual process state so update/reboot flows do not hang forever.
1306+
if !checkProcessAlive() {
1307+
cwlog.DoLogCW("WaitFactQuit: Factorio state was stale; process is no longer alive.")
1308+
SetFactRunning(false, false)
1309+
break
1310+
}
1311+
if time.Since(started) > 2*time.Minute {
1312+
cwlog.DoLogCW("WaitFactQuit: timed out after 2m waiting for Factorio to quit.")
1313+
break
1314+
}
12791315
time.Sleep(time.Millisecond * 100)
12801316
}
12811317
} else {
12821318
for x := 0; x < constants.MaxFactorioCloseWait && FactIsRunning && FactorioBooted && glob.ServerRunning; x++ {
1319+
if !checkProcessAlive() {
1320+
SetFactRunning(false, false)
1321+
break
1322+
}
12831323
time.Sleep(time.Millisecond * 100)
12841324
}
12851325
}

0 commit comments

Comments
 (0)