Repository navigation
[Serve] Expose multiplexed_model_ids on ReplicaDetails - #67276
pardeep-singh wants to merge 5 commits into
Conversation
Record the multiplexed model IDs each replica reports in its actor details, so they appear in the Serve instance details (REST API and dashboard). Closes ray-project#65347 Signed-off-by: Pardeep Singh <pardeep.shergill17@gmail.com>
There was a problem hiding this comment.
Code Review
This pull request exposes multiplexed model IDs in the replica's ReplicaDetails, updating the schema and tests to verify this behavior. Feedback suggests adding a safety check to handle the case where multiplexed_model_ids is None to avoid a potential TypeError when sorting.
|
Thanks @pardeep-singh. Here are my comments:
|
- load_model discards the model ID in a finally block and re-pushes when the load failed or was cancelled (also while waiting for the cache lock), so the controller doesn't keep a stale ID. - ReplicaDetails.multiplexed_model_ids is a Tuple[str, ...] so the frozen model stays hashable, and its description notes that it is empty after a controller restart until the replica's cache changes. Signed-off-by: Pardeep Singh <pardeep.shergill17@gmail.com>
|
@johntaylor-cell thanks for the review. All four are addressed in f340d07:
|
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Reviewed by Cursor Bugbot for commit f340d07. Configure here.
…orted Concurrent load_model calls for the same model shared one set entry, so a waiter that was cancelled or failed removed the ID while another request was still loading it. Track the number of in-flight loads per ID and only drop it, and push again, once no request for it is left. Signed-off-by: Pardeep Singh <pardeep.shergill17@gmail.com>
|
Thanks @pardeep-singh, all four look good. A few small things:
|
…g in tests unload_model_lru sets the push flag right after the evicted model leaves the cache, so an unload that fails or is cancelled while another request for the incoming model is queued still re-pushes. The cancelled-waiter test now checks no re-push is flagged, and test_collect_model_ids uses a Counter. Signed-off-by: Pardeep Singh <pardeep.shergill17@gmail.com>
|
@johntaylor-cell thanks, all four are addressed in b3e9698:
|
|
Thanks @pardeep-singh. All four look good. One last thing is that |
Unloading in shutdown() sets the push flag while the metrics pusher keeps running, so a stopping replica could push its model IDs after the controller removed it. Stop the pusher first. Signed-off-by: Pardeep Singh <pardeep.shergill17@gmail.com>
|
Thanks @johntaylor-cell. Done in 308a983: |

Description
The controller already tracks which multiplexed models each replica has loaded (
DeploymentReplica._multiplexed_model_ids), but the Serve details don't expose it, so there's no way to see from the API or dashboard which replica holds which model.This adds a
multiplexed_model_idsfield toReplicaDetails:schema.py:multiplexed_model_ids: Tuple[str, ...] = Field(default=(), ...). It lists the models loaded or loading on the replica, as last reported to the controller, and is empty for deployments that don't use multiplexing. A tuple keeps the frozenReplicaDetailshashable. The description notes that after a controller restart it stays empty until the replica's model cache next changes.deployment_state.py:DeploymentReplica.record_multiplexed_model_idsalso callsupdate_actor_details(multiplexed_model_ids=tuple(sorted(...))). The IDs are sorted because the replica reports it from a set; this keeps the output stable and lets the unchanged-value fast path from [Serve] Eliminate per-replica-per-tick Pydantic rebuild in update_actor_details #60833 skip rebuilding the details. The routing copy is unchanged.multiplex.py:_ModelMultiplexWrappernow counts in-flight loads per model ID (_model_load_tasksis aCounter).load_modeldecrements the count in afinallyblock, and when no request for the ID is left and the model isn't loaded, it re-pushes. That covers a load that failed or was cancelled, including a cancellation while waiting for the cache lock, and a cancelled request no longer drops an ID that another request is still loading.unload_model_lrualso sets the push flag right after it evicts a model, so an unload that fails or is cancelled still re-pushes.shutdown(), its other caller, stops the metrics pusher before it unloads, so a stopping replica doesn't push after the controller has removed it. Before, a failed load never re-pushed and a cancelled one left the ID in the loading set, so the controller (and routing) kept a stale ID.The field shows up wherever
ReplicaDetailsdoes:get_serve_instance_details(), the REST/api/serve/applications/response and the dashboard API.serve.status()only carries per-deployment replica counts, so it isn't affected.Because the details are serialized with
exclude_unset=True, a replica that never reports (or reports none) leaves the field unset. It's omitted from the JSON and parses back as(), so the existing exact-JSON tests don't change.Related issues
Part of #65347 (the in-replica accessor the issue also asks for isn't included).
Additional information
This builds on @upadhyay74aman's #65370. I kept its schema field and the
update_actor_detailshook-up, adapted to current master after #60833. I left out the in-replicaserve.get_multiplexed_model_ids()accessor and itsapi.py/__init__.pychanges, to keep this to the details field.Why this isn't a duplicate: #65370 was closed by the stale bot without a maintainer review, and no open PR references #65347.
API change: this adds a field to a
stability="stable"public schema. It's additive with a default, so old clients parsing new JSON and new clients parsing old JSON both work.Tests:
serve/tests/unit/test_deployment_state.py: the newtest_record_multiplexed_model_ids_updates_replica_detailsdrivesrecord_request_routing_infoand checkslist_replica_details(). It covers:hash()on the details.It failed before the change with
AttributeError: 'ReplicaDetails' object has no attribute 'multiplexed_model_ids'.serve/tests/test_multiplex.py:test_failed_load_drops_model_idandtest_cancelled_load_drops_model_id[loading|waiting_for_lock]check that the ID leaves the reported set and a re-push is flagged.test_cancelled_waiter_keeps_in_flight_model_idcancels a request waiting on the lock while another loads the same model. It checks the ID stays reported and no re-push is flagged.test_failed_eviction_pushes_with_queued_requestmakes the evicted model's unload fail while another request for the incoming model is queued, and checks a re-push is flagged.test_shutdown_stops_pushing_model_idsruns the pusher on a short interval, callsshutdown()with two models loaded and checks nothing is pushed afterwards.Each fails on master's
multiplex.pyor the change's first version.serve/tests/test_multiplex.py::test_request_routing_infoalso checks the REST-shapedget_serve_details()dict and the parsedServeInstanceDetailsthrough the LRU sequence model1 → {1, 2} → {2, 3}.Notes:
recent_dead_replicaskeeps its last reported list. I can clear it on stop if you'd prefer.AI assistance: I used an AI coding assistant to write this change, its tests and this description.