Repository navigation
fix: hold the server start lock in EvoSci deploy and the WebUI launcher - #661
Conversation
The TUI's ensure_langgraph_dev() and deploy --json hold RUNTIME.lock_file while they decide whether to start a backend and while they start it. The human deploy and the WebUI launcher did not, so a second starter for the same port could kill a backend that was bound but not answering yet as stale, or overwrite its pid file and ownership record. deploy now takes the lock across its port check and the start, waiting up to _FILE_LOCK_TIMEOUT with a spinner. The launcher takes it across the backend decision and the start, waiting in 0.5 s slices that check for a stop(), so a stop while it waits starts nothing; a lock held too long is backend_start_failed with the lock file in fields. Closes EvoScientist#658
The launcher checked for a stop() only before each wait for the start lock, so a stop() in the slice in which the lock was freed still let the decision and the start run. Check once more with the lock held. Name the lock file in the launcher's error detail, word the deploy messages as the rest of deploy does, and keep the deploy and launcher tests' start lock, pid file and sidecar under tmp_path.
|
Note Currently processing new changes in this PR. This may take a few minutes, please wait... ⚙️ Run configuration
📒 Files selected for processing: 6
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Merge Risk: ⚪ Minimal · up to
|
jfilipiuk
left a comment
There was a problem hiding this comment.
Approved. Two non-blocking nits on my side
| self._warnings.append(hint) | ||
| if decision.action == "start": | ||
| self._start_backend() | ||
| with self._start_lock(): |
There was a problem hiding this comment.
Nit: while this waits up to 120 s for another process's start lock, the terminal shows the Starting langgraph dev... spinner from run_webui (webui.py), while deploy shows Waiting for another EvoSci process to start langgraph dev... for the same wait. A progress callback or a status update before the wait would tell the user they are blocked on another process.
There was a problem hiding this comment.
Done in d20f195: WebUILauncher takes an on_lock_wait callback (True when start() has to wait for the lock, False once it holds it), and run_webui uses it to show Waiting for another EvoSci process to start langgraph dev... on its spinner, as deploy does, then goes back to Starting langgraph dev....
|
|
||
| from ..langgraph_dev.manager import _FILE_LOCK_TIMEOUT, RUNTIME | ||
|
|
||
| RUNTIME.pid_dir.mkdir(parents=True, exist_ok=True) |
There was a problem hiding this comment.
Nit: this mkdir (and the lock acquire) now runs outside _start_backend's except Exception, so on a read-only or full config dir the OSError leaves start() as is and run_webui (which catches only LauncherError) shows a traceback instead of the WebUI failed panel. Same in deploy (server.py _start_lock), which before reached the langgraph dev startup failed message. Wrapping it as backend_start_failed would keep the old behaviour.
There was a problem hiding this comment.
Fixed in d20f195: an OSError from the mkdir or the lock acquire is now backend_start_failed with the old langgraph dev startup failed: ... message, so run_webui shows the WebUI failed panel, and deploy prints its startup failed message and exits 1. New tests cover both, for the mkdir and the acquire.
An OSError from the start lock's mkdir or acquire (a read-only or full config dir) escaped the launcher's start() and deploy's _start_lock unhandled, so run_webui showed a traceback instead of the WebUI failed panel and deploy no longer reached its langgraph dev startup failed message. The launcher now raises it as backend_start_failed and deploy prints that message, as both did before the lock. While another process held the lock, run_webui kept showing Starting langgraph dev. WebUILauncher takes an on_lock_wait callback, called with True when start() has to wait and then with False once it holds the lock, and run_webui shows the waiting message deploy uses on its spinner.
Co-authored-by: Xi Zhang <[email protected]>
|
Applied the suggestions and updated the branch; nothing more needed on your side. |
Description
Closes #658.
The human
EvoSci deployand the WebUI launcher now hold the server start lock (RUNTIME.lock_file) across the backend decision and the start, asensure_langgraph_dev()anddeploy --jsonalready do. A second starter for the same port now waits for the first backend instead of killing it as stale or overwriting its pid file and ownership record.deploywaits up to_FILE_LOCK_TIMEOUT(120 s) with a spinner, then refuses the running server as it does today; past that it exits 1 and names the lock file. Most of theserver.pydiff is steps 4 to 7 moving one level in, so hiding whitespace helps.stop()between them and once more with the lock held, so a stop while it waits starts nothing. A lock held too long isbackend_start_failedwithfields={"lock_file": ...}. The front-end preflight stays outside the lock.The new tests in
test_cli_deploy.pyandtest_launcher.py(reusing_LockHolderfromtest_cli_deploy_json.py) fail onmainand pass here. Both modules now use theruntime_pathsfixture, so the lock their tests take stays under tmp_path.Type of change
Checklist
uv run ruff check .passesuv run pytestpasses (on Windows, 13 symlink-privilege and git-config tests fail the same way onmain)Summary by CodeRabbit