Files
2026-07-13 13:17:40 +08:00

103 lines
3.9 KiB
Python

# __replica_rank_start__
from ray import serve
@serve.deployment(num_replicas=4)
class ModelShard:
def __call__(self):
context = serve.get_replica_context()
return {
"rank": context.rank.rank, # Access the integer rank value
"world_size": context.world_size,
}
app = ModelShard.bind()
# __replica_rank_end__
# __reconfigure_rank_start__
from typing import Any
from ray import serve
from ray.serve.schema import ReplicaRank
@serve.deployment(num_replicas=4, user_config={"name": "model_v1"})
class RankAwareModel:
def __init__(self):
context = serve.get_replica_context()
self.rank = context.rank.rank # Extract integer rank value
self.world_size = context.world_size
self.model_name = None
print(f"Replica rank: {self.rank}/{self.world_size}")
async def reconfigure(self, user_config: Any, rank: ReplicaRank):
"""Called when user_config or rank changes."""
self.rank = rank.rank # Extract integer rank value from ReplicaRank object
self.world_size = serve.get_replica_context().world_size
self.model_name = user_config.get("name")
print(f"Reconfigured: rank={self.rank}, model={self.model_name}")
def __call__(self):
return {"rank": self.rank, "model_name": self.model_name}
app2 = RankAwareModel.bind()
# __reconfigure_rank_end__
if __name__ == "__main__":
# __replica_rank_start_run_main__
h = serve.run(app)
# Test that we can get rank information from replicas
seen_ranks = set()
for _ in range(20):
res = h.remote().result()
print(f"Output from __call__: {res}")
assert res["rank"] in [0, 1, 2, 3]
assert res["world_size"] == 4
seen_ranks.add(res["rank"])
# Verify we hit all replicas
print(f"Saw ranks: {sorted(seen_ranks)}")
# Output from __call__: {'rank': 2, 'world_size': 4}
# Output from __call__: {'rank': 1, 'world_size': 4}
# Output from __call__: {'rank': 3, 'world_size': 4}
# Output from __call__: {'rank': 0, 'world_size': 4}
# Output from __call__: {'rank': 0, 'world_size': 4}
# Output from __call__: {'rank': 0, 'world_size': 4}
# Output from __call__: {'rank': 0, 'world_size': 4}
# Output from __call__: {'rank': 3, 'world_size': 4}
# Output from __call__: {'rank': 1, 'world_size': 4}
# Output from __call__: {'rank': 1, 'world_size': 4}
# Output from __call__: {'rank': 0, 'world_size': 4}
# Output from __call__: {'rank': 1, 'world_size': 4}
# Output from __call__: {'rank': 3, 'world_size': 4}
# Output from __call__: {'rank': 2, 'world_size': 4}
# Output from __call__: {'rank': 0, 'world_size': 4}
# Output from __call__: {'rank': 0, 'world_size': 4}
# Output from __call__: {'rank': 2, 'world_size': 4}
# Output from __call__: {'rank': 1, 'world_size': 4}
# Output from __call__: {'rank': 3, 'world_size': 4}
# Output from __call__: {'rank': 0, 'world_size': 4}
# Saw ranks: [0, 1, 2, 3]
# __replica_rank_end_run_main__
# __reconfigure_rank_start_run_main__
h = serve.run(app2)
for _ in range(20):
res = h.remote().result()
assert res["rank"] in [0, 1, 2, 3]
assert res["model_name"] == "model_v1"
seen_ranks.add(res["rank"])
# (ServeReplica:default:RankAwareModel pid=1231505) Replica rank: 0/4
# (ServeReplica:default:RankAwareModel pid=1231505) Reconfigured: rank=0, model=model_v1
# (ServeReplica:default:RankAwareModel pid=1231504) Replica rank: 1/4
# (ServeReplica:default:RankAwareModel pid=1231504) Reconfigured: rank=1, model=model_v1
# (ServeReplica:default:RankAwareModel pid=1231502) Replica rank: 3/4
# (ServeReplica:default:RankAwareModel pid=1231502) Reconfigured: rank=3, model=model_v1
# (ServeReplica:default:RankAwareModel pid=1231503) Replica rank: 2/4
# (ServeReplica:default:RankAwareModel pid=1231503) Reconfigured: rank=2, model=model_v1
# __reconfigure_rank_end_run_main__