Attempt to start web UI when starting Ray. (#269)

* Attempt to start web UI when starting Ray.

* Add instructions for using web UI to cluster documentation.

* Don't check if port 8080 is open.

* Remove print statement.
This commit is contained in:
Robert Nishihara
2017-02-12 15:17:58 -08:00
committed by Philipp Moritz
parent f6ce9dfa6c
commit cb7f6ca9b5
11 changed files with 301 additions and 9 deletions
+97 -2
View File
@@ -26,6 +26,7 @@ PROCESS_TYPE_PLASMA_MANAGER = "plasma_manager"
PROCESS_TYPE_PLASMA_STORE = "plasma_store"
PROCESS_TYPE_GLOBAL_SCHEDULER = "global_scheduler"
PROCESS_TYPE_REDIS_SERVER = "redis_server"
PROCESS_TYPE_WEB_UI = "web_ui"
# This is a dictionary tracking all of the processes of different types that
# have been started by this services module. Note that the order of the keys is
@@ -37,7 +38,8 @@ all_processes = OrderedDict([(PROCESS_TYPE_WORKER, []),
(PROCESS_TYPE_PLASMA_MANAGER, []),
(PROCESS_TYPE_PLASMA_STORE, []),
(PROCESS_TYPE_GLOBAL_SCHEDULER, []),
(PROCESS_TYPE_REDIS_SERVER, [])])
(PROCESS_TYPE_REDIS_SERVER, []),
(PROCESS_TYPE_WEB_UI, [])])
# True if processes are run in the valgrind profiler.
RUN_PHOTON_PROFILER = False
@@ -260,7 +262,7 @@ def start_global_scheduler(redis_address, cleanup=True, redirect_output=False):
Args:
redis_address (str): The address of the Redis instance.
cleanup (bool): True if using Ray in local mode. If cleanup is true, then
this process will be killed by serices.cleanup() when the Python process
this process will be killed by services.cleanup() when the Python process
that imported services exits.
redirect_output (bool): True if stdout and stderr should be redirected to
/dev/null.
@@ -269,6 +271,87 @@ def start_global_scheduler(redis_address, cleanup=True, redirect_output=False):
if cleanup:
all_processes[PROCESS_TYPE_GLOBAL_SCHEDULER].append(p)
def start_webui(redis_address, cleanup=True, redirect_output=False):
"""Attempt to start the Ray web UI.
Args:
redis_address (str): The address of the Redis server.
cleanup (bool): True if using Ray in local mode. If cleanup is True, then
this process will be killed by services.cleanup() when the Python process
that imported services exits.
redirect_output (bool): True if stdout and stderr should be redirected to
/dev/null.
Return:
True if the web UI was successfully started, otherwise false.
"""
webui_backend_filepath = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../webui/backend/ray_ui.py")
webui_directory = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../webui/")
if sys.version_info >= (3, 0):
python_executable = "python"
else:
# If the user is using Python 2, it is still possible to run the webserver
# separately with Python 3, so try to find a Python 3 executable.
try:
python_executable = subprocess.check_output(["which", "python3"]).decode("ascii").strip()
except Exception as e:
print("Not starting the web UI because the web UI requires Python 3.")
return False
with open(os.devnull, "w") as FNULL:
stdout = FNULL if redirect_output else None
stderr = FNULL if redirect_output else None
backend_process = subprocess.Popen([python_executable,
webui_backend_filepath,
"--redis-address", redis_address],
stdout=stdout, stderr=stderr)
time.sleep(0.1)
if backend_process.poll() is not None:
# Failed to start the web UI.
print("The web UI failed to start.")
return False
# Try to start polymer. If this fails, it may that port 8080 is already in
# use. It'd be nice to test for this, but doing so by calling "bind" may start
# using the port and prevent polymer from using it.
try:
with open(os.devnull, "w") as FNULL:
stdout = FNULL if redirect_output else None
stderr = FNULL if redirect_output else None
polymer_process = subprocess.Popen(["polymer", "serve", "--port", "8080"],
cwd=webui_directory,
stdout=stdout, stderr=stderr)
except Exception as e:
print("Failed to start polymer.")
# Kill the backend since it won't work without polymer.
try:
backend_process.kill()
except Exception as e:
pass
return False
# Unfortunately this block of code is unlikely to catch any problems because
# when polymer throws an error on startup, it is typically after several
# seconds.
time.sleep(0.1)
if polymer_process.poll() is not None:
# Failed to start polymer.
print("Failed to serve the web UI with polymer.")
# Kill the backend since it won't work without polymer.
try:
backend_process.kill()
except Exception as e:
pass
return False
if cleanup:
all_processes[PROCESS_TYPE_WEB_UI].append(backend_process)
all_processes[PROCESS_TYPE_WEB_UI].append(polymer_process)
return True
def start_local_scheduler(redis_address,
node_ip_address,
plasma_store_name,
@@ -414,6 +497,7 @@ def start_ray_processes(address_info=None,
redirect_output=False,
include_global_scheduler=False,
include_redis=False,
include_webui=False,
start_workers_from_local_scheduler=True,
num_cpus=None,
num_gpus=None):
@@ -441,6 +525,8 @@ def start_ray_processes(address_info=None,
start a global scheduler process.
include_redis (bool): If include_redis is True, then start a Redis server
process.
include_webui (bool): If True, then attempt to start the web UI. Note that
this is only possible with Python 3.
start_workers_from_local_scheduler (bool): If this flag is True, then start
the initial workers from the local scheduler. Else, start them from
Python.
@@ -579,6 +665,14 @@ def start_ray_processes(address_info=None,
# Make sure that we've started all the workers.
assert(sum(num_workers_per_local_scheduler) == 0)
# Try to start the web UI.
if include_webui:
successfully_started = start_webui(redis_address, cleanup=cleanup,
redirect_output=True)
if successfully_started:
print("View the web UI at http://localhost:8080.")
# Return the addresses of the relevant processes.
return address_info
@@ -681,6 +775,7 @@ def start_ray_head(address_info=None,
redirect_output=redirect_output,
include_global_scheduler=True,
include_redis=True,
include_webui=True,
start_workers_from_local_scheduler=start_workers_from_local_scheduler,
num_cpus=num_cpus,
num_gpus=num_gpus)