Unit tests, extract init_args from main, add option to README

This commit is contained in:
Anton Ermak 2018-01-09 15:59:58 +07:00
parent 5ba255f635
commit 2b754d2662
5 changed files with 54 additions and 11 deletions

View File

@ -159,6 +159,8 @@ optional arguments:
--dry-run-db Force dry run to use a local DB --dry-run-db Force dry run to use a local DB
"tradesv3.dry_run.sqlite" instead of memory DB. Work "tradesv3.dry_run.sqlite" instead of memory DB. Work
only if dry_run is enabled. only if dry_run is enabled.
-w, --watchdog Run under watchdog (restart process if main loop is
stalled)
``` ```
More details on: More details on:
- [How to run the bot](https://github.com/gcarq/freqtrade/blob/develop/docs/bot-usage.md#bot-commands) - [How to run the bot](https://github.com/gcarq/freqtrade/blob/develop/docs/bot-usage.md#bot-commands)

View File

@ -399,12 +399,10 @@ def cleanup() -> None:
exit(0) exit(0)
def main(sysargv=sys.argv[1:]) -> None: def init_args(sysargv) -> Watchdog:
"""
Loads and validates the config and handles the main loop
:return: None
"""
global _CONF global _CONF
args = parse_args(sysargv, args = parse_args(sysargv,
'Simple High Frequency Trading Bot for crypto currencies') 'Simple High Frequency Trading Bot for crypto currencies')
@ -441,13 +439,24 @@ def main(sysargv=sys.argv[1:]) -> None:
) )
else: else:
logger.info('Dry run is disabled. (--dry_run_db ignored)') logger.info('Dry run is disabled. (--dry_run_db ignored)')
watchdog = Watchdog() watchdog = Watchdog()
if args.watchdog_enable: if args.watchdog_enable:
logger.info('Using watchdog to monitor process (--watchdog)') logger.info('Using watchdog to monitor process (--watchdog)')
if not watchdog.start(): if not watchdog.start():
return exit(0)
return args, watchdog
def main(sysargv=sys.argv[1:]) -> None:
"""
Loads and validates the config and handles the main loop
:return: None
"""
global _CONF
args, watchdog = init_args(sysargv)
try: try:
init(_CONF) init(_CONF)

View File

@ -37,6 +37,14 @@ def test_parse_args_backtesting(mocker):
assert call_args.ticker_interval == 5 assert call_args.ticker_interval == 5
def test_init_args():
sysargv = ['--config', 'config.json.example']
args, watchdog = main.init_args(sysargv)
assert args.config == 'config.json.example'
assert main._CONF['stake_currency'] == 'BTC'
assert watchdog.timeout == 300
def test_main_start_hyperopt(mocker): def test_main_start_hyperopt(mocker):
hyperopt_mock = mocker.patch( hyperopt_mock = mocker.patch(
'freqtrade.optimize.hyperopt.start', MagicMock()) 'freqtrade.optimize.hyperopt.start', MagicMock())

View File

@ -0,0 +1,18 @@
from freqtrade.watchdog import Watchdog
def test_watchdog_timeout(caplog):
watchdog = Watchdog(1)
assert(watchdog.run(0) is False)
log = ["Watchdog started", "Kill process due to timeout"]
for line in log:
assert line in caplog.text
def test_watchdog_kill(caplog):
watchdog = Watchdog(1)
watchdog.exit_gracefully(1, 0)
assert(watchdog.run(0) is False)
log = ["Watchdog started", "Watchdog stopped"]
for line in log:
assert line in caplog.text

View File

@ -14,6 +14,10 @@ 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):
self.timeout = timeout
self.heartbeat()
def heartbeat(self) -> None: def heartbeat(self) -> None:
logger.debug("Heartbeat") logger.debug("Heartbeat")
self.shared_heartbeat.value = time.time() self.shared_heartbeat.value = time.time()
@ -24,11 +28,11 @@ class Watchdog:
def kill(self, pid): def kill(self, pid):
logger.info("Stopping pid {}".format(pid)) logger.info("Stopping pid {}".format(pid))
os.kill(pid, signal.SIGTERM) # Better use sigint and then sigterm? if pid:
os.wait() os.kill(pid, signal.SIGTERM) # Better use sigint and then sigterm?
os.wait()
def start(self) -> bool: def start(self) -> bool:
self.heartbeat()
pid = os.fork() pid = os.fork()
if pid != 0: if pid != 0:
# In watchdog proces, run it # In watchdog proces, run it
@ -54,8 +58,10 @@ class Watchdog:
timeout = time.time() - self.shared_heartbeat.value timeout = time.time() - self.shared_heartbeat.value
if timeout > WATCHDOG_TIMEOUT: if timeout > self.timeout:
logger.warning("Kill process due to timeout: {}".format(timeout)) logger.warning("Kill process due to timeout: {}".format(timeout))
if not pid:
return False
self.kill(pid) self.kill(pid)
new_pid = os.fork() new_pid = os.fork()
if new_pid == 0: if new_pid == 0: