feat: judge endpoint resiliency - #2383
Conversation
e197cd6 to
4a76616
Compare
|
/ok to test 4a76616 |
|
/claude review |
|
SHIP WITH CARE — sound feature, well-tested; one operability tail-risk and a config-convention gap, both non-blocking. What this doesAdds endpoint rebinding for vLLM model servers whose backend moves hosts (shared HPC serving jobs): Correctness — looks right
Non-blocking findings (inline)
No async-hang, data-corruption, or public-API concerns. Test coverage is good. |
| ) | ||
|
|
||
| def _resolve_client(self, request: Request) -> NeMoGymAsyncOpenAI: | ||
| self._maybe_rebind_endpoint() |
There was a problem hiding this comment.
NOTE (operability): _maybe_rebind_endpoint() runs a blocking os.stat() (and occasionally open()/read()) on the event loop for every _resolve_client() call — i.e. once per inference request. The feature's target is shared HPC serving jobs, so endpoint_file will typically live on a network FS (Lustre is explicitly called out as a gotcha in CLAUDE.md). A degraded/slow stat there blocks the single-threaded event loop for all concurrent requests on this model server.
BLAST RADIUS: throughput stall under high concurrency when the shared FS is slow — the exact conditions this feature is deployed in. Inference latency normally dominates a sub-ms stat, so this is a tail-risk, not a common case.
FIX: throttle the filesystem check to at most once per N seconds (track last-checked monotonic()), so bursts of requests reuse the cached mtime instead of each issuing a syscall. The grace-period semantics are unaffected since rebinds are rare.
There was a problem hiding this comment.
You're absolutely right about this! Fixed exactly how you suggested.
|
/ok to test 73e0be9 |
|
/claude review |
|
SHIP — solid, well-tested, backward-compatible. This adds endpoint-file rebinding to
One non-blocking NOTE inline about blocking file I/O ( No async-HTTP, verifier/scoring, or dependency-hygiene concerns. |
| return | ||
| self._endpoint_last_check_at = now | ||
| try: | ||
| mtime = os.stat(self.config.endpoint_file).st_mtime |
There was a problem hiding this comment.
NOTE — blocking file I/O on the async event loop. _maybe_rebind_endpoint() is a sync function called from _resolve_client(), which runs inside the async responses()/chat_completions() handlers. os.stat() (and the subsequent open().read()) block the single event loop, stalling all concurrent sessions on this process, not just the caller.
BLAST RADIUS: bounded in practice — the check is throttled to once per endpoint_check_interval_s (10s) and the file read only fires on an mtime change. On a local/tmpfs endpoint file this is microseconds and harmless. But this feature explicitly targets HPC shared serving jobs, and if endpoint_file lives on a networked FS (NFS/Lustre — which CLAUDE.md flags this project runs on), a metadata stall in os.stat freezes every in-flight model request on the process for the duration.
FIX (optional/defense-in-depth): if the endpoint file may live on a cluster FS, run the stat/read via asyncio.to_thread(...) (which requires making the rebind path async) or a thread executor. Given the 10s throttle, author's call — not a blocker.
There was a problem hiding this comment.
I agree with your analysis that this is a well-bounded problem.
Your better solution that you suggest would involve a larger refactor and is not suited for this PR.
73e0be9 to
456ac8c
Compare
456ac8c to
76f4cb2
Compare
76f4cb2 to
127a6ca
Compare
127a6ca to
48244c4
Compare
Signed-off-by: Teodor-Dumitru Ene <teodord.ene@gmail.com>
Signed-off-by: Teodor-Dumitru Ene <teodord.ene@gmail.com>
|
/ok to test 4f62ecb |
48244c4 to
4f62ecb
Compare
Judge models are commonly hosted independently of other jobs. This allows for their reuse.
If a judge model must be rehosted, we cannot allow this to bring down the entire training cluster.
Commonly, training infrastructure have job duration limits. If a judge model meets such a limit in the middle of a training run, it will change addresses, and it needs to communicate this to the rest of the Gym setup.
This PR adds two optional arguments:
max_connection_retriesprevents infinite retries (which cause hangs)endpoint_fileallows the judge model to communicate its address via a local filesystem; this flag comes with associated helper configs.