mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-10-08 12:58:12 +08:00
port retry (#761)
* WIP * import find_available_port method * move method to utils so I can add to eventually add to gui * add fixed-port flag to tests * Update server/utils/utils.py Co-Authored-By: Tony Tung <tonytung@merly.org> * pr review suggestions * pr review suggestions * fix outdated package.json * update error message * simplify find_available_port function * Auto scan for ports unless port is specified. * fix tests * fix comment for find_available_port * lint error * differentiate port error from generic os error * add errno to OSerror * pr review fixes * raise e -> raise * oserror -> socket error
This commit is contained in:
co-authored by
Tony Tung
parent
b9a1e30652
commit
d6040f687a
+13
-2
@@ -1,3 +1,4 @@
|
|||||||
|
import errno
|
||||||
import logging
|
import logging
|
||||||
from os import devnull
|
from os import devnull
|
||||||
from os.path import splitext, basename, getsize
|
from os.path import splitext, basename, getsize
|
||||||
@@ -12,6 +13,7 @@ from server.app.app import Server
|
|||||||
from server.app.util.errors import ScanpyFileError
|
from server.app.util.errors import ScanpyFileError
|
||||||
from server.app.util.utils import custom_format_warning
|
from server.app.util.utils import custom_format_warning
|
||||||
from server.utils.constants import MODES
|
from server.utils.constants import MODES
|
||||||
|
from server.utils.utils import find_available_port
|
||||||
|
|
||||||
|
|
||||||
# anything bigger than this will generate a special message
|
# anything bigger than this will generate a special message
|
||||||
@@ -55,7 +57,8 @@ BIG_FILE_SIZE_THRESHOLD = 100 * 2**20 # 100MB
|
|||||||
show_default=True,
|
show_default=True,
|
||||||
help="Open the web browser after launch.",
|
help="Open the web browser after launch.",
|
||||||
)
|
)
|
||||||
@click.option("--port", "-p", help="Port to run server on.", metavar="", default=5005, show_default=True)
|
@click.option("--port", "-p", help="Port to run server on, if not specified cellxgene will find an available port.",
|
||||||
|
metavar="", show_default=True)
|
||||||
@click.option("--obs-names", default=None, metavar="", help="Name of annotation field to use for observations.")
|
@click.option("--obs-names", default=None, metavar="", help="Name of annotation field to use for observations.")
|
||||||
@click.option("--var-names", default=None, metavar="", help="Name of annotation to use for variables.")
|
@click.option("--var-names", default=None, metavar="", help="Name of annotation to use for variables.")
|
||||||
@click.option("--host", default="127.0.0.1", help="Host IP address")
|
@click.option("--host", default="127.0.0.1", help="Host IP address")
|
||||||
@@ -140,6 +143,9 @@ security risk by including the --scripts flag. Make sure you trust the scripts t
|
|||||||
file_parts = splitext(basename(data))
|
file_parts = splitext(basename(data))
|
||||||
title = file_parts[0]
|
title = file_parts[0]
|
||||||
|
|
||||||
|
if not port:
|
||||||
|
port = find_available_port(host)
|
||||||
|
|
||||||
# Setup app
|
# Setup app
|
||||||
cellxgene_url = f"http://{host}:{port}"
|
cellxgene_url = f"http://{host}:{port}"
|
||||||
|
|
||||||
@@ -197,4 +203,9 @@ security risk by including the --scripts flag. Make sure you trust the scripts t
|
|||||||
f = open(devnull, "w")
|
f = open(devnull, "w")
|
||||||
sys.stdout = f
|
sys.stdout = f
|
||||||
|
|
||||||
server.app.run(host=host, debug=debug, port=port, threaded=True)
|
try:
|
||||||
|
server.app.run(host=host, debug=debug, port=port, threaded=True)
|
||||||
|
except OSError as e:
|
||||||
|
if e.errno == errno.EADDRINUSE:
|
||||||
|
raise click.ClickException("Port is in use, please specify an open port using the --port flag.") from e
|
||||||
|
raise
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class EndPoints(unittest.TestCase):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(cls):
|
def setUpClass(cls):
|
||||||
cls.ps = Popen(["cellxgene", "launch", "example-dataset/pbmc3k.h5ad", "--debug"])
|
cls.ps = Popen(["cellxgene", "launch", "example-dataset/pbmc3k.h5ad", "--debug", "--port", "5005"])
|
||||||
session = requests.Session()
|
session = requests.Session()
|
||||||
for i in range(90):
|
for i in range(90):
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class WithNaNs(unittest.TestCase):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(cls):
|
def setUpClass(cls):
|
||||||
cls.ps = Popen(
|
cls.ps = Popen(
|
||||||
["cellxgene", "launch", "server/test/test_datasets/nan.h5ad", "--debug"]
|
["cellxgene", "launch", "server/test/test_datasets/nan.h5ad", "--debug", "--port", "5005"]
|
||||||
)
|
)
|
||||||
session = requests.Session()
|
session = requests.Session()
|
||||||
for i in range(90):
|
for i in range(90):
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import contextlib
|
||||||
|
import errno
|
||||||
|
import socket
|
||||||
|
|
||||||
|
|
||||||
|
def find_available_port(host, port=5005):
|
||||||
|
"""
|
||||||
|
Helper method to find open port on host. Tries 5000 ports incremented from the specified port
|
||||||
|
"""
|
||||||
|
# Takes approx 2 seconds to do a scan of 5000 ports on my laptop
|
||||||
|
num_ports_to_try = 5000
|
||||||
|
for port_to_try in range(port, port + num_ports_to_try):
|
||||||
|
with contextlib.closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
|
||||||
|
try:
|
||||||
|
s.bind((host, port_to_try))
|
||||||
|
return port_to_try
|
||||||
|
except socket.error:
|
||||||
|
pass
|
||||||
|
raise socket.error(errno.EADDRINUSE, f"No port in range {port} - {port + num_ports_to_try - 1} available.")
|
||||||
Reference in New Issue
Block a user