@@ -18,6 +18,7 @@ async def transcribe(audio_url: str): ...
1818 def load_model(): ... # worker startup hook
1919"""
2020
21+ import asyncio
2122import inspect
2223from typing import (
2324 TYPE_CHECKING ,
@@ -30,7 +31,7 @@ def load_model(): ... # worker startup hook
3031 Type ,
3132)
3233
33- from .context import Context , current_context
34+ from .context import Context , block , current_context
3435from .discovery_state import DiscoveryInvocationError , in_discovery
3536from .errors import InvalidResourceError
3637from .invoker import Invoker , StreamInvoker
@@ -64,7 +65,7 @@ def __init__(
6465 if stamped and not spec .schedule :
6566 spec .schedule = stamped
6667
67- self .remote = Invoker (self ._remote_async )
68+ self .remote = Invoker (self ._remote_async , sync_factory = self . _remote_sync )
6869 self .stream = StreamInvoker (self ._stream_async )
6970 self .spawn = Invoker (self ._spawn_async )
7071 self .job = Invoker (self ._job_async )
@@ -117,22 +118,46 @@ def local(self, *args: Any, **kwargs: Any) -> Any:
117118 function is async."""
118119 return self ._fn (* args , ** kwargs )
119120
121+ def _call_local_sync (self , * args : Any , ** kwargs : Any ) -> Any :
122+ result = self ._fn (* args , ** kwargs )
123+ return list (result ) if inspect .isgenerator (result ) else result
124+
125+ @staticmethod
126+ async def _await_local_result (result : Any ) -> Any :
127+ if inspect .isawaitable (result ):
128+ result = await result
129+ if inspect .isasyncgen (result ):
130+ return [chunk async for chunk in result ]
131+ return list (result ) if inspect .isgenerator (result ) else result
132+
133+ def _remote_sync (self , * args : Any , ** kwargs : Any ) -> Any :
134+ if (
135+ current_context () is Context .WORKER
136+ and self ._is_current_worker ()
137+ and not inspect .iscoroutinefunction (self ._fn )
138+ and not inspect .isasyncgenfunction (self ._fn )
139+ ):
140+ self ._guard_discovery ()
141+ self .spec .validate ()
142+ result = self ._call_local_sync (* args , ** kwargs )
143+ if inspect .isawaitable (result ) or inspect .isasyncgen (result ):
144+ return block (self ._await_local_result (result ))
145+ return result
146+ return block (self ._remote_async (* args , ** kwargs ))
147+
120148 async def _remote_async (self , * args : Any , ** kwargs : Any ) -> Any :
121149 self ._guard_discovery ()
122150 self .spec .validate ()
123151 ctx = current_context ()
124152
125153 if ctx is Context .WORKER and self ._is_current_worker ():
126- result = self ._fn (* args , ** kwargs )
127- if inspect .isawaitable (result ):
128- result = await result
129- # generators aggregate, matching the deployed worker's
130- # return_aggregate_stream output for .remote()
131- if inspect .isasyncgen (result ):
132- return [chunk async for chunk in result ]
133- if inspect .isgenerator (result ):
134- return list (result )
135- return result
154+ if inspect .iscoroutinefunction (self ._fn ) or inspect .isasyncgenfunction (
155+ self ._fn
156+ ):
157+ result = self ._fn (* args , ** kwargs )
158+ else :
159+ result = await asyncio .to_thread (self ._call_local_sync , * args , ** kwargs )
160+ return await self ._await_local_result (result )
136161
137162 target = await self ._app ._resolve (self .spec )
138163 payload = target .build_payload (self ._fn , self .spec , args , kwargs )
0 commit comments