Match a pre-upgrade studio.pid to the blocked port before falling back
This commit is contained in:
parent
279afd1024
commit
7db3ee073c
2 changed files with 83 additions and 1 deletions
|
|
@ -875,7 +875,38 @@ def _own_studio_on_port(port: int, host: str) -> "int | None":
|
|||
# None (unverifiable) counts as ours: refusing beats a silent duplicate.
|
||||
if _pid_is_studio_backend(pid, [created]) is not False:
|
||||
return pid
|
||||
return None
|
||||
return _legacy_studio_on_port(port)
|
||||
|
||||
|
||||
def _legacy_studio_on_port(port: int) -> "int | None":
|
||||
"""A pre-upgrade server recorded only its PID, so match it to the listener.
|
||||
|
||||
Falling back past one leaves it running while `_write_pid_file` overwrites the
|
||||
only record of it. When the listener is unknowable, assume it is ours.
|
||||
"""
|
||||
record = _read_pid_record(_PID_FILE)
|
||||
if record is None:
|
||||
return None
|
||||
pid, created, _address = record
|
||||
if not _pid_alive(pid):
|
||||
return None
|
||||
# A current build writes a per-port file too, so its port is already known --
|
||||
# and this port's records were just checked. Only unported records get here.
|
||||
if any(r and r[0] == pid for r in _per_port_records()):
|
||||
return None
|
||||
blocker = _get_pid_on_port(port)
|
||||
if blocker is not None and blocker[0] != pid:
|
||||
return None
|
||||
if _pid_is_studio_backend(pid, [created]) is False:
|
||||
return None
|
||||
return pid
|
||||
|
||||
|
||||
def _per_port_records() -> "list[tuple[int, float | None, str | None] | None]":
|
||||
try:
|
||||
return [_read_pid_record(p) for p in _studio_root().glob(PID_FILE_GLOB)]
|
||||
except OSError:
|
||||
return []
|
||||
|
||||
|
||||
def _abort_already_running(pid: int, port: int) -> "NoReturn":
|
||||
|
|
|
|||
|
|
@ -228,6 +228,57 @@ def test_legacy_records_do_not_match_a_training_run(monkeypatch):
|
|||
assert run._pid_is_studio_backend(9999) is False
|
||||
|
||||
|
||||
def test_a_legacy_server_on_the_port_is_recognised(tmp_path, monkeypatch):
|
||||
# Pre-upgrade servers wrote only studio.pid. Falling back past one strands it
|
||||
# and then overwrites its record.
|
||||
monkeypatch.setattr(run, "_get_pid_on_port", lambda p: (8550, "python"))
|
||||
(tmp_path / "studio.pid").write_text("8550", encoding = "utf-8")
|
||||
|
||||
assert run._own_studio_on_port(8901, "127.0.0.1") == 8550
|
||||
|
||||
|
||||
def test_a_legacy_record_for_a_different_listener_falls_back(tmp_path, monkeypatch):
|
||||
# jupyter holds the port; the legacy server is elsewhere. Keep falling back.
|
||||
monkeypatch.setattr(run, "_get_pid_on_port", lambda p: (117, "jupyter-lab"))
|
||||
(tmp_path / "studio.pid").write_text("8550", encoding = "utf-8")
|
||||
|
||||
assert run._own_studio_on_port(8901, "127.0.0.1") is None
|
||||
|
||||
|
||||
def test_an_unknowable_listener_treats_the_legacy_record_as_ours(tmp_path, monkeypatch):
|
||||
# No psutil: _get_pid_on_port can't say. Refusing beats a silent duplicate.
|
||||
monkeypatch.setattr(run, "_get_pid_on_port", lambda p: None)
|
||||
(tmp_path / "studio.pid").write_text("8550", encoding = "utf-8")
|
||||
|
||||
assert run._own_studio_on_port(8901, "127.0.0.1") == 8550
|
||||
|
||||
|
||||
def test_a_dead_legacy_record_falls_back(tmp_path, monkeypatch):
|
||||
monkeypatch.setattr(run, "_pid_alive", lambda pid: False)
|
||||
monkeypatch.setattr(run, "_get_pid_on_port", lambda p: None)
|
||||
(tmp_path / "studio.pid").write_text("8550", encoding = "utf-8")
|
||||
|
||||
assert run._own_studio_on_port(8901, "127.0.0.1") is None
|
||||
|
||||
|
||||
def test_a_current_server_elsewhere_does_not_block_a_foreign_port(tmp_path, monkeypatch):
|
||||
# Current builds write studio.pid too. Without psutil the legacy check can't
|
||||
# see the listener, so it must not claim our 8901 server holds jupyter's 8888.
|
||||
monkeypatch.setattr(run, "_get_pid_on_port", lambda p: None)
|
||||
(tmp_path / "studio-8901-5000.pid").write_text("5000\n\n127.0.0.1", encoding = "utf-8")
|
||||
(tmp_path / "studio.pid").write_text("5000", encoding = "utf-8")
|
||||
|
||||
assert run._own_studio_on_port(8888, "127.0.0.1") is None
|
||||
|
||||
|
||||
def test_a_per_port_record_is_preferred_over_the_legacy_one(tmp_path, monkeypatch):
|
||||
monkeypatch.setattr(run, "_get_pid_on_port", lambda p: (8550, "python"))
|
||||
(tmp_path / "studio-8901-8600.pid").write_text("8600\n\n127.0.0.1", encoding = "utf-8")
|
||||
(tmp_path / "studio.pid").write_text("8550", encoding = "utf-8")
|
||||
|
||||
assert run._own_studio_on_port(8901, "127.0.0.1") == 8600
|
||||
|
||||
|
||||
def test_our_studio_on_another_bind_address_does_not_abort(tmp_path):
|
||||
# Our server holds ::1:8889; binding 127.0.0.1:8889 is not a conflict with us,
|
||||
# so fall through to the next port instead of refusing.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue