Fix telegram bot process checks on Windows
Some checks are pending
ci / test (macos-latest) (push) Waiting to run
ci / test (ubuntu-latest) (push) Waiting to run
ci / test (windows-latest) (push) Waiting to run

This commit is contained in:
patriceckhart 2026-06-13 17:39:14 +02:00
parent 7f954ceaa3
commit 798174c22c
3 changed files with 101 additions and 33 deletions

View file

@ -7,7 +7,6 @@ import (
"path/filepath"
"strconv"
"strings"
"syscall"
"time"
)
@ -68,42 +67,15 @@ func IsRunning(zotHome string) (int, bool, error) {
if pid <= 0 {
return 0, false, nil
}
proc, err := os.FindProcess(pid)
alive, err := processAlive(pid)
if err != nil {
return pid, false, nil
}
// signal 0 is POSIX's "does the process exist?" probe. On Windows
// os.Process is always usable and Signal(0) returns nil, so we'd
// miss stale pids; acceptable for the macos/linux-first audience.
if err := proc.Signal(syscall.Signal(0)); err != nil {
if errors.Is(err, os.ErrProcessDone) || errors.Is(err, syscall.ESRCH) {
return pid, false, nil
}
// Other errors (EPERM) mean the process exists but we can't
// inspect it; treat as running.
return pid, true, nil
}
return pid, true, nil
return pid, alive, nil
}
// StopProcess sends SIGTERM to pid and waits up to graceful for it to
// exit, then escalates to SIGKILL. Returns nil if the process is gone.
// StopProcess asks pid to exit and waits up to graceful for it to stop,
// then escalates to a forced kill. Returns nil if the process is gone.
func StopProcess(pid int, graceful time.Duration) error {
proc, err := os.FindProcess(pid)
if err != nil {
return err
}
_ = proc.Signal(syscall.SIGTERM)
deadline := time.Now().Add(graceful)
for time.Now().Before(deadline) {
if err := proc.Signal(syscall.Signal(0)); err != nil {
if errors.Is(err, os.ErrProcessDone) || errors.Is(err, syscall.ESRCH) {
return nil
}
}
time.Sleep(100 * time.Millisecond)
}
_ = proc.Kill()
return nil
return stopProcess(pid, graceful)
}

View file

@ -0,0 +1,44 @@
//go:build !windows
package telegram
import (
"errors"
"os"
"syscall"
"time"
)
func processAlive(pid int) (bool, error) {
proc, err := os.FindProcess(pid)
if err != nil {
return false, err
}
if err := proc.Signal(syscall.Signal(0)); err != nil {
if errors.Is(err, os.ErrProcessDone) || errors.Is(err, syscall.ESRCH) {
return false, nil
}
// Other errors (EPERM) mean the process exists but we can't inspect it.
return true, nil
}
return true, nil
}
func stopProcess(pid int, graceful time.Duration) error {
proc, err := os.FindProcess(pid)
if err != nil {
return err
}
_ = proc.Signal(syscall.SIGTERM)
deadline := time.Now().Add(graceful)
for time.Now().Before(deadline) {
alive, err := processAlive(pid)
if err != nil || !alive {
return nil
}
time.Sleep(100 * time.Millisecond)
}
_ = proc.Kill()
return nil
}

View file

@ -0,0 +1,52 @@
//go:build windows
package telegram
import (
"errors"
"os"
"time"
"golang.org/x/sys/windows"
)
const stillActive = 259
func processAlive(pid int) (bool, error) {
h, err := windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION, false, uint32(pid))
if err != nil {
if errors.Is(err, windows.ERROR_INVALID_PARAMETER) {
return false, nil
}
if errors.Is(err, windows.ERROR_ACCESS_DENIED) {
return true, nil
}
return false, err
}
defer windows.CloseHandle(h)
var code uint32
if err := windows.GetExitCodeProcess(h, &code); err != nil {
return false, err
}
return code == stillActive, nil
}
func stopProcess(pid int, graceful time.Duration) error {
proc, err := os.FindProcess(pid)
if err != nil {
return err
}
_ = proc.Signal(os.Interrupt)
deadline := time.Now().Add(graceful)
for time.Now().Before(deadline) {
alive, err := processAlive(pid)
if err != nil || !alive {
return nil
}
time.Sleep(100 * time.Millisecond)
}
_ = proc.Kill()
return nil
}