Looking for Senior AWS Serverless Architects & Engineers?
Let's TalkWhat are the essential elements?
The entire definition of Durable Functions is always created in code, meaning that you don’t need an extra description language, e.g. YAML, JSON, etc., to get started. However, you have to know these three types of functions that are to describe your workflow.
- Client function
This is a common function with one of the available triggers, e.g. HTTP trigger, Queue storage trigger, etc. Using a durable client output binding makes the function a specific one. This function is used to start a new instance of orchestration and thanks to the durable client, it is possible to return an orchestration status to a caller.
[FunctionName("ClientFunction")]
public static async Task<IActionResult> ClientFunctionStart(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
[DurableClient] IDurableOrchestrationClient client,
ILogger log)
{
string name = req.Query["name"];
string instanceId = Guid.NewGuid().ToString();
await client.StartNewAsync("OrchestrationFunction", instanceId, name);
return client.CreateCheckStatusResponse(req, instanceId);
}
Client function triggered by HttpRequest
- Orchestrator function
This is the heart of Durable Functions. Using this function you can define execution order, setup exceptions handling and deal with a state.
[FunctionName("OrchestrationFunction")]
public static async Task<string> OrchestrationStart(
[OrchestrationTrigger] IDurableOrchestrationContext context, ILogger logger)
{
var result = "";
var input = context.GetInput<string>();
try
{
result = await context.CallActivityAsync<string>("CreateMessage", input);
await context.CallActivityAsync("SendMessageToQueue", result);
}
catch (Exception ex)
{
logger.LogError("Something went wrong", ex);
return string.Empty;
}
return result;
}
Orchestrator function with described workflow
- Activity function
The main goal of the activity function is to get a job done. You can use it to calculate something and to get any information from external sources. Moreover, it accepts an input parameter that is passed from an orchestrator function. After a task is done, you can return a value that is further processed by an orchestrator function.
[FunctionName("CreateMessage")]
public static async Task<string> FirstActivityFunction([ActivityTrigger] string input)
{
return $"Hello {input}!";
}
[FunctionName("SendMessageToQueue")]
public static async Task SecondActivityFunction(
[ActivityTrigger] string input,
[Queue("messages", Connection = "StorageConnection")]
IAsyncCollector<string> messages)
{
await messages.AddAsync(input);
await messages.FlushAsync();
}
Two activity functions with different responsibilities
There is one more called an ‘entity function’. It defines operations for reading and updating a small piece of state. Entity function is only available in Durable Functions 2.0 and above. Because of that, we will cover it in the next article.
What languages does it support?
Currently, Durable Functions supports C#, F#, JavaScript. Moreover, the goal of the Azure Functions team is to cover all available languages within Azure Functions so, you can expect that Durable Functions will be available for languages like Python, Java, etc. sooner or later.
Summary
If you need to describe a workflow, don’t hesitate to use Durable Functions. It is one of the best options to pass a state between functions and it allows you to stay where you fell the best — in code. Once you use it, you will always see new use cases. If you are not sure if your architecture is good or you have a problem with starting, call us. We, at Serverless Guru, are here to help you.