Passing Values to a Orchestrator function in durable functions

So I wanted to get a short post out here on a handy little trick that I actually had a pretty hard time finding the answer to. So I’ve been doing work with Durable functions lately in Python, and really enjoy the possible options this opens up for longer running or complex server-less operations.

That being said, I did run into a headache early on in the form of how do I pass values from the initial request to the other parts of the function. So here’s a short post on how to do that so that hopefully the next person doesn’t have as hard of a time finding the answer.

So when you have a durable function, you essentially get 3+ pieces, but at the minimum its 3 pieces.

  • HttpStart: This is the code that receives all Http requests for durable functions and then acts as a router, to push them to the correct Orchestrator.
  • Orchestrator: This is the function that will be longer running and used to manage state ongoing.
  • Activity: These are the smaller functions that are called upon by the orchestrator to do the work being asked for.

Now the problem is that normally I would pull from an http request in a function in the following way:

async def main(req: func.HttpRequest, starter: str) -> func.HttpResponse:
    payload = json.loads(req.get_body().decode())
    logging.info(f"Trigger payload = {payload}")

See though the problem with this is that the actual request that kicked off the function is only accessible to the HttpStart. So now, you need to figure out a way to pass this to the orchestrator, and if I’m being honest, the best way to do that isn’t clear.

Part of the reason it isn’t clear, is that Durable functions do a lot of work to encapsulate the inner workings of how they manage state. Which I’m thankful for, but it made this harder.

But after much head-scratching, if I figured it out, and here it is:

async def main(req: func.HttpRequest, starter: str) -> func.HttpResponse:
    client = df.DurableOrchestrationClient(starter)

    function_name = req.route_params["functionName"]
    requestBody = json.loads(req.get_body().decode())

    instance_id = await client.start_new(function_name, client_input=requestBody)

Now when you use core tools, all the wiring is pre-built for you. Strongly recommend that. But if you leverage the “client_input” parameter off the DurableOrchestrationClient, you can pass a json serialized paylod over to the orchestrator.

From the orchestrator’s side, the code looks like the following:

requestBody : str = context.get_input()

Now one of the limitations I found was that you could only pass one parameter this way, so the easy workaround was to implement a complex object that I would then serialize containing all relevant data.

28