Skip to content

Commit

Permalink
Tailcalls
Browse files Browse the repository at this point in the history
  • Loading branch information
pelletier committed Jan 30, 2024
1 parent feb7001 commit 432f6f4
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 0 deletions.
15 changes: 15 additions & 0 deletions src/dispatch/coroutine.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,21 @@ def callback(cls, state: Any, calls: None | list[Call] = None) -> Output:

return Output(coroutine_pb2.ExecuteResponse(poll=poll))

@classmethod
def tailcall(cls, call: Call) -> Output:
"""Exit the coroutine instructing the orchestrator to call the provided
coroutine."""
input_bytes = _pb_any_pickle(call.input)
x = coroutine_pb2.Call(
coroutine_uri=call.coroutine_uri,
coroutine_version=call.coroutine_version,
correlation_id=call.correlation_id,
input=input_bytes,
)
return Output(
coroutine_pb2.ExecuteResponse(exit=coroutine_pb2.Exit(tail_call=x))
)


# Note: contrary to other classes here Call is not just a wrapper around its
# associated protobuf class, because it is reasonable for a human to write the
Expand Down
15 changes: 15 additions & 0 deletions tests/test_fastapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,3 +291,18 @@ def mycoro(input: Input) -> Output:
self.assertEqual("foo", resp.exit.result.error.type)
self.assertEqual("bar", resp.exit.result.error.message)
self.assertEqual(Status.THROTTLED, resp.status)

def test_tailcall(self):
@self.app.dispatch_coroutine()
def other_coroutine(input: Input) -> Output:
return Output.value(f"Hello {input.input}")

@self.app.dispatch_coroutine()
def mycoro(input: Input) -> Output:
return Output.tailcall(other_coroutine.call_with(42))

resp = self.execute(mycoro)
self.assertEqual(other_coroutine.uri, resp.exit.tail_call.coroutine_uri)
self.assertEqual(
42, dispatch.coroutine._any_unpickle(resp.exit.tail_call.input)
)

0 comments on commit 432f6f4

Please sign in to comment.