feat(standalone): 新增单机模式,KILOSTAR_MODE=standalone 时去掉 Ray 依赖
通过 StandaloneProxy 适配层让 .remote() 调用在单机模式下透明降级为 asyncio 协程调用,7 个 Actor 和 workflow task 均可在纯 asyncio 环境运行, 启动快、资源占用低。分布式模式行为完全不变。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
"""standalone_proxy 适配层单元测试。
|
||||
|
||||
验证 StandaloneProxy / _MethodProxy / actor_class / remote_task
|
||||
在单机模式下的行为是否正确模拟了 Ray Actor Handle 的 .remote() 接口。
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import pytest
|
||||
|
||||
from kilostar.utils import standalone_proxy
|
||||
from kilostar.utils.standalone_proxy import StandaloneProxy, _MethodProxy
|
||||
|
||||
|
||||
class TestMethodProxy:
|
||||
def test_sync_method(self):
|
||||
def add(a, b):
|
||||
return a + b
|
||||
|
||||
proxy = _MethodProxy(add)
|
||||
result = asyncio.get_event_loop().run_until_complete(proxy.remote(2, 3))
|
||||
assert result == 5
|
||||
|
||||
def test_async_method(self):
|
||||
async def async_add(a, b):
|
||||
return a + b
|
||||
|
||||
proxy = _MethodProxy(async_add)
|
||||
result = asyncio.get_event_loop().run_until_complete(proxy.remote(4, 6))
|
||||
assert result == 10
|
||||
|
||||
|
||||
class TestStandaloneProxy:
|
||||
def test_method_call(self):
|
||||
class FakeActor:
|
||||
def greet(self, name):
|
||||
return f"hello {name}"
|
||||
|
||||
proxy = StandaloneProxy(FakeActor())
|
||||
future = proxy.greet.remote("world")
|
||||
result = asyncio.get_event_loop().run_until_complete(future)
|
||||
assert result == "hello world"
|
||||
|
||||
def test_async_method_call(self):
|
||||
class FakeActor:
|
||||
async def compute(self, x):
|
||||
return x * 2
|
||||
|
||||
proxy = StandaloneProxy(FakeActor())
|
||||
future = proxy.compute.remote(7)
|
||||
result = asyncio.get_event_loop().run_until_complete(future)
|
||||
assert result == 14
|
||||
|
||||
def test_attribute_access(self):
|
||||
class FakeActor:
|
||||
def __init__(self):
|
||||
self.name = "test"
|
||||
|
||||
proxy = StandaloneProxy(FakeActor())
|
||||
assert proxy.name == "test"
|
||||
|
||||
|
||||
class TestActorClass:
|
||||
def test_standalone_returns_class_unchanged(self, monkeypatch):
|
||||
monkeypatch.setattr(standalone_proxy, "_STANDALONE", True)
|
||||
|
||||
@standalone_proxy.actor_class
|
||||
class MyActor:
|
||||
def do_work(self):
|
||||
return 42
|
||||
|
||||
instance = MyActor()
|
||||
assert instance.do_work() == 42
|
||||
|
||||
def test_standalone_class_is_plain_python(self, monkeypatch):
|
||||
monkeypatch.setattr(standalone_proxy, "_STANDALONE", True)
|
||||
|
||||
@standalone_proxy.actor_class
|
||||
class MyActor:
|
||||
pass
|
||||
|
||||
assert not hasattr(MyActor, "remote")
|
||||
assert not hasattr(MyActor, "options")
|
||||
|
||||
|
||||
class TestRemoteTask:
|
||||
def test_sync_task(self, monkeypatch):
|
||||
monkeypatch.setattr(standalone_proxy, "_STANDALONE", True)
|
||||
|
||||
@standalone_proxy.remote_task
|
||||
def multiply(a, b):
|
||||
return a * b
|
||||
|
||||
future = multiply.remote(3, 4)
|
||||
result = asyncio.get_event_loop().run_until_complete(future)
|
||||
assert result == 12
|
||||
|
||||
def test_async_task(self, monkeypatch):
|
||||
monkeypatch.setattr(standalone_proxy, "_STANDALONE", True)
|
||||
|
||||
@standalone_proxy.remote_task
|
||||
async def async_multiply(a, b):
|
||||
return a * b
|
||||
|
||||
future = async_multiply.remote(5, 6)
|
||||
result = asyncio.get_event_loop().run_until_complete(future)
|
||||
assert result == 30
|
||||
Reference in New Issue
Block a user