Azure Durable Functions — Orquestração de fluxos de trabalho

Renicius Pagotto Fostaini
9 min readSep 15, 2022

--

E ai pessoal, no post de hoje falaremos sobre Azure Durable Functions que é basicamente um complemento do post anterior, onde abordamos sobre o Azure Functions.

Para quem não leu o post sobre Azure Functions, esse é o link para acessar.

O que é Azure Durable Functions?

Para um melhor entendimento, abaixo temos um trecho da definição fornecida pela própria documentação.

As Durable Functions são uma extensão do Azure Functions que permite escrever funções com estado. A extensão permite definir fluxos de trabalho com estado pela escrita de funções de orquestrador e entidades com estado pela escrita de funções de entidade usando o modelo de programação do Azure Functions. Nos bastidores, a extensão gerencia o estado, os pontos de verificação e as reinicializações para você, permitindo que você se concentre na lógica de negócios.

Em resumo, o Azure Durable Functions é um recurso stateful e que permite a orquestração de fluxos de trabalho de modo facilitado.

Linguagens suportadas

O Azure Durable Functions suporta a maioria das linguagens que é suportado pelo Azure Functions, porém existem requisitos específicos para cada linguagem conforme é exibido na imagem abaixo.

Tipos de Azure Durable Functions

Atualmente está disponível 4 tipos de implementações para as Durable Functions, são elas:

  • Orchestrator functions;
  • Activity functions;
  • Entity functions;
  • Client functions.

Orchestrator functions

As orquestrator functions descrevem como as ações devem ser executadas e a ordem de execução das mesmas. Em sua declaração possuem um atributo chamado OrchestrationTrigger.

Activity functions

Uma activity function é basicamente uma unidade de trabalho a ser realizada, ou seja, é um fluxo de trabalho com apenas uma responsabilidade e que é gerenciada pelo orchestrator.

Um bom exemplo para esse tipo de função é um sistema de comércio eletrônico onde é possível criar um pedido de compra. Podemos utilizar um orquestrador para gerenciar todo o processo de criação e finalização de um pedido, porém para cada etapa temos algum tipo de tarefa como verificação de estoque, processar o pagamento e envio de email de notificação para o cliente e para cada uma dessas etapas podemos utilizar uma activity function para realizar essa tarefa de verificação e aplicação de regras de negócio. Essas funções podem ser processadas em paralelo ou em sequência.

Em sua declaração, possui o atributo ActivityTrigger para sua identificação.

Entity Functions

As entities functions são responsáveis por alteração de estado de uma entidade, ou seja, ela é responsável por ler, atualizar e persistir alguma informação de alguma entidade.

Em sua declaração, possui o atributo EntityTrigger para sua identificação.

Client functions

São funções não orquestradoras e que são acionadas por eventos externos, por exemplo, um Azure Event Hub ou ainda funções que utilizam como saída um binding output, que são conexões com recursos externos.

Padrões de aplicação

Para a implementação do Azure Durable Functions, possuímos alguns padrões disponíveis, que nos auxiliam para cada tipo de cenário, são eles:

  • Function chaining;
  • Fan-in/Fan-out;
  • Async HTTP APIs;
  • Monitoring;
  • Human interaction;
  • Aggregator

Iremos abordar neste artigo o padrão Function chaining e o padrão Fan-in/Fan-out, porém caso queiram conhecer um pouco mais sobre os outros padrões, essa é a documentação oficial que explica todos eles.

Padrão Function Chaining

Function chaining, ou encadeamento de função em tradução, é quando a execução das funções possui uma ordem específica. Nesse caso, a resposta de uma função é utilizada como parâmetro de entrada da próxima função a ser executada.

A comunicação entre as funções podem acontecer de diversos meios, porém HTTP e mensageria são os mais comuns.

Fan-in/Fan-out Pattern

Com esse padrão de implementação, é possível a execução paralela de multíplas funções. Uma vez iniciado o processamento dessas funções, será aguardado o término do processamento de todas elas e como resposta teremos uma agregação das respostas de todas as funções.

Autenticação

O Azure Durable Functions oferece suporte nativo a chamadas de APIs que aceitam token do Azure Active Directory (AAD).

Nesse link, você encontra mais informações sobre essa funcionalidade e um exemplo de código.

Uso do Azure Storage

Assim como o Azure Functions utiliza o Azure Storage para gerenciamento de escalabilidade, o Azure Durable Functions necessita utilizar um storage para realizar o gerenciamento de processamento e armazenamento de estado, visto que ele é um serviço stateful.

Precificação

O Azure Durable Function possui a mesma precificação do Azure Functions, porém existem algumas particularidades em seu funcionamento que pode afetar o custo final.

Nesse link, você encontra mais informações a respeito desses comportamentos do Azure Durable Functions e como é a cobrança é afetada.

Show me the code!

Na demonstração de hoje, vamos implementar os padrões Chaining e Fan-in/Fan-out e utilizar o Orchestrator function e o Activity function.

Para o desenvolvimento das funções, utilizaremos o Visual Studio 2022, o SDK do Azure que é integrado ao VS e o .NET 6.

Criação de Azure Function / Durable Functions

No Visual Studio, selecione a opção novo projeto e escolha o tipo de projeto Azure Functions, como mostrado na imagem abaixo.

Na próxima tela, precisamos definir o nome do projeto, a localização do projeto em nosso computador e o nome da solução, sendo essa última opção apenas para novos projetos em novas soluções (solutions).

Nessa última tela, vamos selecionar a versão do Function worker, que nada mais é do que a versão do .NET utilizada; na opção Function é exibido vários tipos possíveis de implementação.

Por fim, deixaremos a opção do Azurite marcado para que não seja necessário a criação de um storage no Azure. O Azurite é um emulador de storage e que é necessário ao utilizar Azure Functions / Durable Functions.

Authorization Level

O authorization level é uma opção que definimos na função e que indica se alguma chave é obrigatória ser passada na invocação da função. Basicamente é um meio de proteção contra acesso indevido ou não autorizado.

Atualmente possuímos 3 tipos de acessos, são eles:

  • Anonymous: Nenhuma chave é requerida para invocar a função;
  • Functions: É requerida uma chave de função simples;
  • Admin: Uma master key é requerido para invocar a função.

Essas chaves são geradas na criação de um recurso de Azure Functions e são acessíveis através do portal do Azure, conforme mostrado na imagem abaixo.

Function Chaining sem Activity functions

Para essa implementação, iremos criar duas funções do tipo HTTP Trigger, que é uma função que tem a capacidade de expor um endpoint para interação. a primeira função será responsável por gerar uma string aleatória e a segunda função será resposnável por gerar um número aleatório.

Além dessa funções, iremos implementar um orquestrador (Orchestrator function) que será responsável pelo gerenciamento das chamadas aos endpoints de ambas as funções e pelo armazenamento do estado, ou seja, da resposta das funções.

Na imagem abaixo, podemos ver a implementação da nossa primeira função que é responsável por gerar uma string aleatória.

Na imagem abaixo, podemos ver a implementação da nossa segunda função que é responsável por gerar um número aleatório.

Por último, na imagem abaixo é demonstrado a implementação do nosso orquestrador de fluxo.

Na implementação, temos dois métodos, o primeiro que é o HttpStart que é nossa durable function em si e que possui o atributo HttpTrigger, que informa que nossa durable function será acionada através de uma requisição HTTP.

O segundo método com o nome RunOrchestrator é de fato o nosso orquestrador de fluxo e possui um atributo chamado OrchestrationTrigger indicando o seu tipo. Esse método é responsável por gerenciar as requisições HTTP e agrupar as respostas em um array, que é definido pela variável outputs.

Resumindo o funcionamento, a durable function uma vez acionada via requisição HTTP, chama o orquestrador de fluxo que basicamente gerencia as requisições para outras funções, agrupa a resposta e retorna para a função anterior que ao final armazena o estado final do processamento, ou seja, a resposta das duas funções HTTP.

Function Chaining com Activity functions

Um outro tipo de implementação para esse orquestrador de fluxo, seria utilizando o activity functions, conforme demosntrado na imagem abaixo

Nessa nova implementação, as requisições HTTP que estavam dentro do orquestrador foram dividas em duas acitivity function, cada uma dessas funções possuem apenas uma responsabilidade, com isso temos uma melhora na coesão da nossa implementação.

Perceba que cada função tem um atributo ActivityTrigger que representa que aquele método é uma unidade de trabalho com responsabilidade única.

Implementação Fan-in/Fan-out

Nessa demonstração, vamos utilizar duas funções do tipo HTTP que implementamos no exemplo anterior e uma nova implementação em nosso orquestrador de fluxo.

A estrutura da durable function é basicamente a mesma com os dois métodos padrão, onde a mudança apenas ocorre no algoritmo do orquestrador, conforme é demosntrado abaixo.

A estrutura permanece a mesma, porém dentro do nosso orquestrador, temos uma implementação simples, onde as requisições HTTP serão disparadas paralelamente e ao final as respostas agrupadas em uma variável.

Acessando uma Durable Function

Na execução do nosso projeto, é sempre fornecida uma URL para que possamos realizar a requisição de processamento da nossa durable function.

Basicamente o padrão de URL é sempre o mesmo, mudando apenas o final, onde temos o nome da função da nossa durable function e que é representada dentro do código pelo atributo FunctionName que fica na linha acima da declaração do método.

Para esse cenário de implementação, tanto requisições POST, como requisições GET podem iniciar o processamento de nossa função.

Vale pontuar que utilizamos a trigger HTTP para inicialização da nossa durable function, porém pode ser utilizada outras implementações, conforme o contexto de aplicação.

Análise de Resposta do Azure Durable Functions

Ao invocarmos nossa durable function, ao final do processamento é fornecida algumas URLs, dentre elas, a primeira URL é utilizada para obter a resposta em si.

Como toda durable function é stateful, ou seja, é possível o gerenciamento de estado, a nossa resposta ja está armazenada, sendo apenas necessário acessa-la. Para isso selecionamos a primeira URL da propriedade statusQueryGetUri e realizamos uma requisição via navegador ou postman, como preferir.

E com isso, finalmente temos a resposta final de todo o processamento feito conforme é demonstrado na imagem acima.

Nesse json de resposta temos o nome da função que foi executada, o status de processamento e o output que basicamente é o agrupamento das respostas para as funções HTTP que tinhamos implementado.

Um ponto interessante para abordar é que não importa quantas vezes seja realizada uma requisição a essa URL, a resposta será sempre a mesma visto que estamos apenas acessando o estado final da nossa durable function.

Para respostas diferentes é necessário primeiro requisitar um processamento da nossa durable function e depois acessar a URL de resposta para obter uma resposta diferente.

Conclusões

Chegamos ao fim do post de hoje e como explicado, as Durable Functions são utilizadas como orquestradoras de fluxo e os cenários para a sua utilização são vários, ainda mais quando falamos de orquestração de fluxo que é um recurso muito utilizado em vários projetos empresáriais.

Porém como sempre digo, é necessário uma análise profunda do seu projeto para saber se o Azure Durable Functions é uma boa escolha ou não.

E ai, gostou desse post? Quer conversar um pouco mais sobre Azure Durable Functions? Deixe um comentário com suas dúvidas e idéias ou entre em contato comigo através do LinkedIn.

GitHub: reniciuspagotto/azure-durable-functions (github.com)

Referências

Durable Functions Overview — Azure | Microsoft Docs

Azure Durable Functions and its Key Concepts | Serverless360

Durable Functions: Orquestração de tarefas com Azure — YouTube

--

--