Try stop with SIGINT first, pass timeout to constructor
This commit is contained in:
parent
2b754d2662
commit
21779b6d0d
@ -16,3 +16,24 @@ def test_watchdog_kill(caplog):
|
|||||||
log = ["Watchdog started", "Watchdog stopped"]
|
log = ["Watchdog started", "Watchdog stopped"]
|
||||||
for line in log:
|
for line in log:
|
||||||
assert line in caplog.text
|
assert line in caplog.text
|
||||||
|
|
||||||
|
|
||||||
|
def test_try_kill_failed(mocker):
|
||||||
|
mocker.patch("os.kill")
|
||||||
|
mocker.patch("os.waitpid", return_value=(0, 0))
|
||||||
|
watchdog = Watchdog(1, 1)
|
||||||
|
assert watchdog.try_kill(0) is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_try_kill_success(mocker):
|
||||||
|
mocker.patch("os.kill")
|
||||||
|
mocker.patch("os.waitpid", return_value=(0, 1))
|
||||||
|
watchdog = Watchdog(1, 1)
|
||||||
|
assert watchdog.try_kill(0) is True
|
||||||
|
|
||||||
|
|
||||||
|
def test_try_kill_error(mocker):
|
||||||
|
mocker.patch("os.kill")
|
||||||
|
mocker.patch("os.waitpid", side_effect=OSError)
|
||||||
|
watchdog = Watchdog(1, 1)
|
||||||
|
assert watchdog.try_kill(0) is True
|
||||||
|
@ -7,6 +7,7 @@ from multiprocessing import Value
|
|||||||
logger = logging.getLogger('freqtrade.watchdog')
|
logger = logging.getLogger('freqtrade.watchdog')
|
||||||
|
|
||||||
WATCHDOG_TIMEOUT = 300
|
WATCHDOG_TIMEOUT = 300
|
||||||
|
KILL_TIMEOUT = 60
|
||||||
|
|
||||||
|
|
||||||
class Watchdog:
|
class Watchdog:
|
||||||
@ -14,8 +15,9 @@ class Watchdog:
|
|||||||
shared_heartbeat = Value('d', 0.0)
|
shared_heartbeat = Value('d', 0.0)
|
||||||
kill_signal = None
|
kill_signal = None
|
||||||
|
|
||||||
def __init__(self, timeout=WATCHDOG_TIMEOUT):
|
def __init__(self, timeout=WATCHDOG_TIMEOUT, kill_timeout=KILL_TIMEOUT):
|
||||||
self.timeout = timeout
|
self.timeout = timeout
|
||||||
|
self.kill_timeout = kill_timeout
|
||||||
self.heartbeat()
|
self.heartbeat()
|
||||||
|
|
||||||
def heartbeat(self) -> None:
|
def heartbeat(self) -> None:
|
||||||
@ -26,11 +28,27 @@ class Watchdog:
|
|||||||
logger.warning("Kill signal: {}".format(signum))
|
logger.warning("Kill signal: {}".format(signum))
|
||||||
self.kill_signal = signum
|
self.kill_signal = signum
|
||||||
|
|
||||||
|
def try_kill(self, pid):
|
||||||
|
os.kill(pid, signal.SIGINT)
|
||||||
|
for count in range(0, self.kill_timeout):
|
||||||
|
try:
|
||||||
|
pid, err_code = os.waitpid(pid, os.WNOHANG)
|
||||||
|
if pid != 0 or err_code != 0:
|
||||||
|
return True
|
||||||
|
time.sleep(1)
|
||||||
|
except OSError:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def kill(self, pid):
|
def kill(self, pid):
|
||||||
logger.info("Stopping pid {}".format(pid))
|
logger.info("Stopping pid {}".format(pid))
|
||||||
if pid:
|
if pid:
|
||||||
os.kill(pid, signal.SIGTERM) # Better use sigint and then sigterm?
|
if self.try_kill(pid):
|
||||||
os.wait()
|
logger.info("Process finished gracefully")
|
||||||
|
else:
|
||||||
|
logger.warning("Process not responded, kill by SIGTERM")
|
||||||
|
os.kill(pid, signal.SIGTERM)
|
||||||
|
os.wait()
|
||||||
|
|
||||||
def start(self) -> bool:
|
def start(self) -> bool:
|
||||||
pid = os.fork()
|
pid = os.fork()
|
||||||
|
Loading…
Reference in New Issue
Block a user