Permalink
Browse files

Ephemeris sleep - hopefully makes serve tests a bit more robust.

Copying the function until I migrate it and release Ephemeris with changes.
  • Loading branch information...
jmchilton committed May 24, 2018
1 parent 016b923 commit b12b117622c51edc6f1879b207cb6dc97ba08e91
Showing with 101 additions and 29 deletions.
  1. +84 −0 planemo/galaxy/ephemeris_sleep.py
  2. +5 −12 planemo/galaxy/serve.py
  3. +5 −5 tests/test_cmd_serve.py
  4. +7 −12 tests/test_utils.py
@@ -0,0 +1,84 @@
#!/usr/bin/env python
'''Utility to do a blocking sleep until a Galaxy instance is responsive.
This is useful in docker images, in RUN steps, where one needs to wait
for a currently starting Galaxy to be alive, before API requests can be
made successfully.
The script functions by making repeated requests to
``http(s)://fqdn/api/version``, an API which requires no authentication
to access.'''

import sys
import time
from argparse import ArgumentParser

import requests

try:
from .common_parser import get_common_args
except ImportError:
# This won't stay in Planemo long, main no longer functional.
get_common_args = None


def _parser():
'''Constructs the parser object'''
parent = get_common_args(login_required=False)
parser = ArgumentParser(parents=[parent], usage="usage: python %(prog)s <options>",
description="Script to sleep and wait for Galaxy to be alive.")
parser.add_argument("--timeout",
default=0, type=int,
help="Galaxy startup timeout in seconds. The default value of 0 waits forever")
return parser


def _parse_cli_options():
"""
Parse command line options, returning `parse_args` from `ArgumentParser`.
"""
parser = _parser()
return parser.parse_args()


def sleep(galaxy_url, verbose=False, timeout=0):
count = 0
while True:
try:
result = requests.get(galaxy_url + '/api/version')
try:
result = result.json()
if verbose:
sys.stdout.write("Galaxy Version: %s\n" % result['version_major'])
break
except ValueError:
if verbose:
sys.stdout.write("[%02d] No valid json returned... %s\n" % (count, result.__str__()))
sys.stdout.flush()
except requests.exceptions.ConnectionError as e:
if verbose:
sys.stdout.write("[%02d] Galaxy not up yet... %s\n" % (count, str(e)[0:100]))
sys.stdout.flush()
count += 1

# If we cannot talk to galaxy and are over the timeout
if timeout != 0 and count > timeout:
sys.stderr.write("Failed to contact Galaxy\n")
return False

time.sleep(1)

return True


def main():
"""
Main function
"""
options = _parse_cli_options()

galaxy_alive = sleep(galaxy_url=options.galaxy, verbose=options.verbose, timeout=options.timeout)
exit_code = 0 if galaxy_alive else 1
sys.exit(exit_code)


if __name__ == "__main__":
main()
@@ -3,11 +3,11 @@

import contextlib
import os
import time

from planemo import io
from planemo import network_util
from .config import galaxy_config
from .ephemeris_sleep import sleep
from .run import (
run_galaxy_command,
)
@@ -50,19 +50,12 @@ def _serve(ctx, runnables, **kwds):
io.warn(message)
raise Exception(message)
host = kwds.get("host", "127.0.0.1")

timeout = 500
galaxy_url = "http://%s:%s" % (host, port)
ctx.vlog("Waiting for URL %s" % galaxy_url)
assert network_util.wait_http_service(galaxy_url, timeout=timeout)
time.sleep(.1)
ctx.vlog("Waiting for URL %s" % galaxy_url)
assert network_util.wait_http_service(galaxy_url, timeout=timeout)
time.sleep(5)
ctx.vlog("Waiting for URL %s" % galaxy_url)
assert network_util.wait_http_service(galaxy_url, timeout=timeout)
version_url = "%s/api/version" % galaxy_url
ctx.vlog("Waiting for URL %s" % version_url)
assert network_util.wait_http_service(version_url, timeout=timeout)
galaxy_alive = sleep(galaxy_url, verbose=ctx.verbose, timeout=timeout)
if not galaxy_alive:
raise Exception("Attempted to serve Galaxy at %s, but it failed to start in %d seconds." % (galaxy_url, timeout))
config.install_workflows()
if kwds.get("pid_file"):
real_pid_file = config.pid_file
@@ -6,9 +6,9 @@
from planemo.galaxy import api
from planemo.io import kill_pid_file
from .test_utils import (
cli_daemon_service,
cli_daemon_galaxy,
CliTestCase,
launch_and_wait_for_service,
launch_and_wait_for_galaxy,
mark,
PROJECT_TEMPLATES_DIR,
skip_if_environ,
@@ -95,13 +95,13 @@ def _test_serve_profile(self, *db_options):
"--profile", new_profile,
]
serve_cmd = self._serve_command_list(extra_args)
with cli_daemon_service(self._runner, self._pid_file, self._port, serve_cmd):
with cli_daemon_galaxy(self._runner, self._pid_file, self._port, serve_cmd):
user_gi = self._user_gi
assert len(user_gi.histories.get_histories(name=TEST_HISTORY_NAME)) == 0
user_gi.histories.create_history(TEST_HISTORY_NAME)

# TODO: Pretty sure this is getting killed, but we should verify.
with cli_daemon_service(self._runner, self._pid_file, self._port, serve_cmd):
with cli_daemon_galaxy(self._runner, self._pid_file, self._port, serve_cmd):
assert len(user_gi.histories.get_histories(name=TEST_HISTORY_NAME)) == 1

def setUp(self):
@@ -118,7 +118,7 @@ def _user_gi(self):
return user_gi

def _launch_thread_and_wait(self, func, args=[]):
launch_and_wait_for_service(self._port, func, [args])
launch_and_wait_for_galaxy(self._port, func, [args])

def _run_shed(self, serve_args=[]):
return self._run(serve_args=serve_args, serve_cmd="shed_serve")
@@ -6,7 +6,6 @@
import os
import shutil
import threading
import time
import traceback
from sys import version_info
from tempfile import mkdtemp
@@ -16,9 +15,9 @@

from planemo import cli
from planemo import io
from planemo import network_util
from planemo import shed
from planemo.config import PLANEMO_CONFIG_ENV_PROP
from planemo.galaxy.ephemeris_sleep import sleep
from .shed_app_test_utils import (
mock_shed,
setup_mock_shed,
@@ -305,14 +304,14 @@ def check_exit_code(runner, command_list, exit_code=0):


@contextlib.contextmanager
def cli_daemon_service(runner, pid_file, port, command_list, exit_code=0):
t = launch_and_wait_for_service(port, check_exit_code, args=[runner, command_list, exit_code])
def cli_daemon_galaxy(runner, pid_file, port, command_list, exit_code=0):
t = launch_and_wait_for_galaxy(port, check_exit_code, args=[runner, command_list, exit_code])
yield
io.kill_pid_file(pid_file)
t.join(timeout=60)


def launch_and_wait_for_service(port, func, args=[]):
def launch_and_wait_for_galaxy(port, func, args=[]):
"""Run func(args) in a thread and wait on port for service.
Service should remain up so check network a few times, this prevents
@@ -323,19 +322,15 @@ def launch_and_wait_for_service(port, func, args=[]):
t = threading.Thread(target=target)
t.daemon = True
t.start()
time.sleep(5)
assert network_util.wait_net_service("127.0.0.1", port, timeout=600)
time.sleep(1)
assert network_util.wait_net_service("127.0.0.1", port, timeout=600)
time.sleep(1)
assert network_util.wait_net_service("127.0.0.1", port, timeout=600)
sleep("http://localhost:%d" % port, timeout=600)
return t


# TODO: everything should be considered "exported".
__all__ = (
"assert_exists",
"launch_and_wait_for_service",
"cli_daemon_galaxy",
"launch_and_wait_for_galaxy",
"TestCase",
"CliTestCase",
)

0 comments on commit b12b117

Please sign in to comment.