Try stop with SIGINT first, pass timeout to constructor

This commit is contained in:
Anton Ermak 2018-01-09 19:23:24 +07:00
parent 2b754d2662
commit 21779b6d0d
2 changed files with 42 additions and 3 deletions

View File

@ -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

View File

@ -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()