Restrições de código de função do Orchestrator
Durable Functions é uma extensão de Funções do Azure que lhe permite criar aplicações com estado. Pode utilizar uma função de orquestrador para orquestrar a execução de outras funções duráveis numa aplicação de funções. As funções do Orchestrator têm estado, são fiáveis e potencialmente de longa duração.
Restrições de código do orquestrador
As funções do Orchestrator utilizam a origem de eventos para garantir uma execução fiável e para manter o estado da variável local. O comportamento de repetição do código do orquestrador cria restrições no tipo de código que pode escrever numa função de orquestrador. Por exemplo, as funções do orquestrador têm de ser deterministas: uma função do orquestrador será repetida várias vezes e tem de produzir sempre o mesmo resultado.
Utilizar APIs deterministas
Esta secção fornece algumas diretrizes simples que ajudam a garantir que o código é determinista.
As funções do Orchestrator podem chamar qualquer API nos respetivos idiomas de destino. No entanto, é importante que as funções do orquestrador chamem apenas APIs deterministas. Uma API determinista é uma API que devolve sempre o mesmo valor dada a mesma entrada, independentemente de quando ou com que frequência é chamada.
As secções seguintes fornecem orientações sobre APIs e padrões que deve evitar porque não são deterministas. Estas restrições aplicam-se apenas às funções do orquestrador. Outros tipos de funções não têm tais restrições.
Nota
Estão descritos abaixo vários tipos de restrições de código. Infelizmente, esta lista não é abrangente e alguns casos de utilização podem não ser abrangidos. O mais importante a considerar ao escrever código do orquestrador é se uma API que está a utilizar é determinista. Depois de se sentir confortável em pensar desta forma, é fácil compreender que APIs são seguras de utilizar e que não são necessárias para fazer referência a esta lista documentada.
Datas e horas
As APIs que devolvem a data ou hora atuais não sãondeterminísticas e nunca devem ser utilizadas em funções de orquestrador. Isto deve-se ao facto de cada repetição da função do orquestrador produzir um valor diferente. Em vez disso, deve utilizar a API equivalente Durable Functions para obter a data ou hora atual, que permanece consistente entre as repetições.
Não utilize DateTime.Now
as APIs , DateTime.UtcNow
ou equivalentes para obter a hora atual. As classes como Stopwatch
também devem ser evitadas. Para funções de orquestrador .NET no processo, utilize a IDurableOrchestrationContext.CurrentUtcDateTime
propriedade para obter a hora atual. Para funções de orquestrador isolado .NET, utilize a TaskOrchestrationContext.CurrentDateTimeUtc
propriedade para obter a hora atual.
DateTime startTime = context.CurrentUtcDateTime;
// do some work
TimeSpan totalTime = context.CurrentUtcDateTime.Subtract(startTime);
GUIDs e UUIDs
As APIs que devolvem um GUID ou UUID aleatórios não sãondeterminísticas porque o valor gerado é diferente para cada repetição. Dependendo do idioma que utilizar, poderá estar disponível uma API incorporada para gerar GUIDs deterministas ou UUIDs. Caso contrário, utilize uma função de atividade para devolver um GUID ou UUID gerado aleatoriamente.
Não utilize APIs como Guid.NewGuid()
para gerar GUIDs aleatórios. Em vez disso, utilize a API do objeto de contexto para gerar um GUID aleatório seguro para a repetição do NewGuid()
orquestrador.
Guid randomGuid = context.NewGuid();
Nota
Os GUIDs gerados com APIs de contexto de orquestração são UUIDs do Tipo 5.
Números aleatórios
Utilize uma função de atividade para devolver números aleatórios a uma função de orquestrador. Os valores devolvidos das funções de atividade são sempre seguros para repetição porque são guardados no histórico de orquestração.
Em alternativa, um gerador de números aleatórios com um valor de seed fixo pode ser utilizado diretamente numa função de orquestrador. Esta abordagem é segura desde que seja gerada a mesma sequência de números para cada repetição de orquestração.
Enlaces
Uma função do orquestrador não pode utilizar enlaces, incluindo os enlaces de cliente de orquestração e de cliente de entidade . Utilize sempre enlaces de entrada e saída a partir de uma função de cliente ou atividade. Isto é importante porque as funções do orquestrador podem ser repetidas várias vezes, causando E/S não administrativa e duplicada com sistemas externos.
Variáveis estáticas
Evite utilizar variáveis estáticas nas funções do orquestrador porque os respetivos valores podem ser alterados ao longo do tempo, o que resulta num comportamento de runtime não administrativo. Em vez disso, utilize constantes ou limite a utilização de variáveis estáticas para funções de atividade.
Nota
Mesmo fora das funções do orquestrador, a utilização de variáveis estáticas no Funções do Azure pode ser problemática por uma variedade de razões, uma vez que não há garantia de que o estado estático persista em múltiplas execuções de funções. As variáveis estáticas devem ser evitadas, exceto em casos de utilização muito específicos, como colocação em cache na memória no melhor esforço em funções de atividade ou entidade.
Variáveis de ambiente
Não utilize variáveis de ambiente em funções de orquestrador. Os respetivos valores podem ser alterados ao longo do tempo, o que resulta num comportamento de runtime não administrativo. Se uma função do orquestrador precisar de uma configuração definida numa variável de ambiente, tem de transmitir o valor de configuração para a função do orquestrador como uma entrada ou como o valor devolvido de uma função de atividade.
Rede e HTTP
Utilize funções de atividade para efetuar chamadas de rede de saída. Se precisar de fazer uma chamada HTTP a partir da função do orquestrador, também pode utilizar as APIs HTTP duráveis.
APIs de bloqueio de threads
Bloquear APIs como "suspensão" pode causar problemas de desempenho e dimensionamento para funções do orquestrador e deve ser evitado. No Funções do Azure Plano de consumo, podem até resultar em custos de tempo de execução desnecessários. Utilize alternativas para bloquear APIs quando estiverem disponíveis. Por exemplo, utilize temporizadores Duráveis para criar atrasos seguros para repetição e não conte para o tempo de execução de uma função orquestrador.
APIs Assíncronas
O código do orchestrator nunca deve iniciar nenhuma operação assíncrona, exceto as definidas pelo objeto de contexto do acionador de orquestração. Por exemplo, nunca utilize Task.Run
, Task.Delay
e HttpClient.SendAsync
no .NET ou setTimeout
no setInterval
JavaScript. Uma função do orquestrador só deve agendar trabalhos assíncronos com as APIs do Durable SDK, como funções de atividade de agendamento. Qualquer outro tipo de invocações assíncronas deve ser efetuada dentro das funções de atividade.
Funções JavaScript assíncronas
Declare sempre as funções do orquestrador JavaScript como funções de gerador síncronas. Não pode declarar funções de orquestrador JavaScript como async
porque o runtime Node.js não garante que as funções assíncronas sejam deterministas.
Coroutines Python
Não pode declarar funções de orquestrador python como coroutines. Por outras palavras, nunca declare funções do orquestrador python com a async
palavra-chave porque a semântica coroutina não está alinhada com o modelo de repetição Durable Functions. Tem de declarar sempre as funções do orquestrador Python como geradores, o que significa que deve esperar que a context
API utilize yield
em vez de await
.
APIs de threading .NET
O Durable Task Framework executa o código do orquestrador num único thread e não consegue interagir com outros threads. Executar continuações assíncronas num thread de conjunto de trabalho, a execução de uma orquestração pode resultar em impasses ou execuções não administrativas. Por este motivo, as funções do orquestrador quase nunca devem utilizar APIs de threading. Por exemplo, nunca utilize ConfigureAwait(continueOnCapturedContext: false)
numa função de orquestrador. Isto garante que as continuações de tarefas são executadas no original da função orchestrator SynchronizationContext
.
Nota
O Durable Task Framework tenta detetar a utilização acidental de threads não orquestradores em funções de orquestrador. Se encontrar uma violação, a arquitetura gera uma exceção NonDeterministicOrchestrationException . No entanto, este comportamento de deteção não detetará todas as violações e não deve depender dele.
Controlo de versões
Uma orquestração durável pode funcionar continuamente durante dias, meses, anos ou até eternamente. Quaisquer atualizações de código feitas a Durable Functions aplicações que afetam orquestrações inacabadas podem interromper o comportamento de repetição das orquestrações. É por isso que é importante planear cuidadosamente ao fazer atualizações ao código. Para obter uma descrição mais detalhada sobre como controlar a versão do código, consulte o artigo sobre controlo de versões.
Tarefas duráveis
Nota
Esta secção descreve os detalhes de implementação interna do Durable Task Framework. Pode utilizar funções duráveis sem conhecer estas informações. Destina-se apenas a ajudá-lo a compreender o comportamento de repetição.
As tarefas que podem aguardar em segurança nas funções do orquestrador são ocasionalmente referidas como tarefas duráveis. O Durable Task Framework cria e gere estas tarefas. Os exemplos são as tarefas devolvidas por CallActivityAsync
, WaitForExternalEvent
e CreateTimer
nas funções de orquestrador .NET.
Estas tarefas duráveis são geridas internamente por uma lista de TaskCompletionSource
objetos no .NET. Durante a repetição, estas tarefas são criadas como parte da execução do código do orchestrator. São concluídos à medida que o despachante enumera os eventos do histórico correspondentes.
As tarefas são executadas de forma síncrona com um único thread até que todo o histórico tenha sido reproduzido. As tarefas duráveis que não estão concluídas até ao final da repetição do histórico têm ações adequadas executadas. Por exemplo, uma mensagem pode ser colocada em fila para chamar uma função de atividade.
A descrição desta secção sobre o comportamento do runtime deve ajudá-lo a compreender por que motivo uma função do orquestrador não pode utilizar await
ou yield
numa tarefa não periódica. Existem duas razões: o thread de despachante não pode esperar pela conclusão da tarefa e qualquer chamada de retorno dessa tarefa pode danificar potencialmente o estado de controlo da função do orquestrador. Algumas verificações de runtime estão em vigor para ajudar a detetar estas violações.
Para saber mais sobre como o Durable Task Framework executa funções de orquestrador, consulte o código fonte da Durable Task no GitHub. Em particular, veja TaskOrchestrationExecutor.cs e TaskOrchestrationContext.cs.