diff --git a/src/forge/controller/service/interface.py b/src/forge/controller/service/interface.py index eb6f0ddd7..5b7e2f884 100644 --- a/src/forge/controller/service/interface.py +++ b/src/forge/controller/service/interface.py @@ -101,6 +101,36 @@ async def fanout(self, *args: P.args, **kwargs: P.kwargs) -> List[R]: result = await self.service.call_all(self.endpoint_name, *args, **kwargs) return result + async def choose(self, *args: P.args, **kwargs: P.kwargs) -> R: + raise NotImplementedError( + "You tried to use choose() on a service, not an actor. " + "Services only support route() and fanout()." + ) + + async def call(self, *args: P.args, **kwargs: P.kwargs) -> List[R]: + raise NotImplementedError( + "You tried to use call() on a service, not an actor. " + "Services only support route() and fanout()." + ) + + async def call_one(self, *args: P.args, **kwargs: P.kwargs) -> R: + raise NotImplementedError( + "You tried to use a call_one() on a service, not an actor. " + "Services only support route() and fanout()." + ) + + async def broadcast(self, *args: P.args, **kwargs: P.kwargs) -> List[R]: + raise NotImplementedError( + "You tried to use broadcast() on a service, not an actor. " + "Services only support route() and fanout()." + ) + + async def generate(self, *args: P.args, **kwargs: P.kwargs): + raise NotImplementedError( + "You tried to use generate() on a service, not an actor. " + "Services only support route() and fanout()." + ) + class ServiceEndpointV2(Generic[P, R]): """An endpoint object specific to services. diff --git a/tests/unit_tests/test_service.py b/tests/unit_tests/test_service.py index 612e4ff42..31a912542 100644 --- a/tests/unit_tests/test_service.py +++ b/tests/unit_tests/test_service.py @@ -214,6 +214,42 @@ async def test_multiple_services_isolated_configs(): await service2.shutdown() +@pytest.mark.asyncio +@pytest.mark.timeout(5) +async def test_service_endpoint_monarch_method_error(): + """Test that calling Monarch-style methods on a service endpoint raises NotImplementedError.""" + service = await Counter.options(procs=1, num_replicas=1).as_service(0) + try: + # Try to call a Monarch-style method and check for the error + with pytest.raises( + NotImplementedError, + match="You tried to use a call_one", + ): + await service.value.call_one() + with pytest.raises( + NotImplementedError, + match="You tried to use broadcast", + ): + await service.value.broadcast() + with pytest.raises( + NotImplementedError, + match="You tried to use generate", + ): + await service.value.generate() + with pytest.raises( + NotImplementedError, + match="You tried to use choose", + ): + await service.value.choose() + with pytest.raises( + NotImplementedError, + match="You tried to use call", + ): + await service.value.call() + finally: + await service.shutdown() + + # Core Functionality Tests