Skip to content

Commit 9e304ac

Browse files
committed
deterministically find available port
1 parent d1c4be8 commit 9e304ac

File tree

2 files changed

+24
-6
lines changed

2 files changed

+24
-6
lines changed

idom/server/utils.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
from socket import socket
22
from types import ModuleType
3-
from typing import Type, Any, List, cast
3+
from typing import Type, Any, List
44
from importlib import import_module
5+
from contextlib import closing
56

67

78
def find_builtin_server_type(type_name: str) -> Type[Any]:
@@ -34,8 +35,16 @@ def find_builtin_server_type(type_name: str) -> Type[Any]:
3435
)
3536

3637

37-
def find_available_port(host: str) -> int:
38-
"""Get a port that's available for the given host"""
39-
sock = socket()
40-
sock.bind((host, 0))
41-
return cast(int, sock.getsockname()[1])
38+
def find_available_port(host: str, port_min: int = 8000, port_max: int = 9000) -> int:
39+
"""Get a port that's available for the given host and port range"""
40+
for port in range(port_min, port_max):
41+
with closing(socket()) as sock:
42+
try:
43+
sock.bind((host, port))
44+
except OSError:
45+
pass
46+
else:
47+
return port
48+
raise RuntimeError(
49+
f"Host {host!r} has no available port in range {port_max}-{port_max}"
50+
)

tests/test_server/test_utils.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import pytest
2+
from idom.server.utils import find_available_port
3+
4+
5+
def test_find_available_port():
6+
assert find_available_port("localhost", port_min=5000, port_max=6000)
7+
with pytest.raises(RuntimeError, match="no available port"):
8+
# check that if port range is exhausted we raise
9+
find_available_port("localhost", port_min=0, port_max=0)

0 commit comments

Comments
 (0)