Coordene um conjunto de ações distribuídas como uma única operação. Se alguma das ações falhar, tente processar as falhas de forma transparente ou anule o trabalho que foi realizado para que toda a operação seja bem-sucedida ou falhe como um todo. Este procedimento pode adicionar resiliência a um sistema distribuído ao permitir que recupere e repita as ações que falharam devido a exceções transitórias, falhas de longa duração e falhas de processamento.
Contexto e problema
Uma aplicação realiza tarefas que incluem uma série de passos, alguns dos quais podem invocar serviços remotos ou aceder a recursos remotos. Os passos individuais podem ser independentes entre si, mas são orquestrados pela lógica da aplicação que implementa a tarefa.
Sempre que possível, a aplicação deve garantir que a tarefa é executada até à conclusão e resolve qualquer falha que possa ocorrer ao aceder aos serviços ou recursos remotos. As falhas podem ocorrer por diversos motivos. Por exemplo, a rede pode estar inativa, as comunicações podem estar interrompidas, um serviço remoto pode não estar a responder ou pode estar num estado instável, ou um recurso remoto pode estar temporariamente inacessível, talvez devido a restrições de recursos. Em muitos casos, as falhas são transitórias e podem ser processadas com o padrão Repetição.
Se a aplicação detetar uma falha mais permanente da qual não consegue recuperar facilmente, esta terá de ter a capacidade para restaurar o sistema para um estado consistente e garantir a integridade de toda a operação.
Solução
O padrão do Supervisor do Agente do Scheduler define os seguintes atores. Estes atores orquestram os passos a serem executados como parte da tarefa geral.
O Scheduler faz com que os passos que compõem a tarefa sejam executados e orquestra a sua operação. Estes passos podem ser combinados num pipeline ou num fluxo de trabalho. O Scheduler é responsável por assegurar que os passos neste fluxo de trabalho são executados na ordem correta. À medida que cada etapa é executada, o Agendador registra o estado do fluxo de trabalho, como "etapa ainda não iniciada", "etapa em execução" ou "etapa concluída". As informações de estado também devem incluir um limite máximo do tempo permitido para a etapa terminar, chamado de tempo completo. Se um passo precisar de acesso a um serviço ou a recurso remotos, o Scheduler invocará o Agente adequado, transmitindo-lhe os detalhes do trabalho a ser executado. O Agendador normalmente se comunica com um Agente usando mensagens assíncronas de solicitação/resposta. Tal pode ser implementado com filas, mas pode também utilizar outras tecnologias de mensagens distribuídas.
O Scheduler realiza uma função semelhante no Gestor de Processos no padrão de Gestor de Processos. O fluxo de trabalho real é, normalmente, definido e implementado por um motor de fluxo de trabalho controlado pelo Scheduler. Esta abordagem desacopla a lógica de negócio no fluxo de trabalho do Scheduler.
O Agente contém a lógica que encapsula uma chamada para um serviço remoto ou o acesso a um recurso remoto mencionado por um passo numa tarefa. Por norma, cada Agente encapsula num wrapper chamadas para um único serviço ou recurso e implementa o processamento de erros adequado e a lógica de repetição (sujeitas a uma restrição de tempo limite, descrita mais à frente). Ao implementar a lógica de repetição, passe um identificador estável em todas as tentativas de repetição para que o serviço remoto possa usá-lo para qualquer lógica de desduplicação que possa ter. Se os passos no fluxo de trabalho a serem executados pelo Scheduler utilizarem vários serviços e recursos em diferentes passos, cada passo poderá mencionar um Agente diferente (este é um detalhe de implementação do padrão).
O Supervisor monitoriza o estado dos passos da tarefa a ser realizada pelo Scheduler. Ele é executado periodicamente (a frequência será específica do sistema) e examina o status das etapas mantidas pelo Agendador. Se detetar que algum excedeu o limite de tempo ou falhou, tomará as medidas para que o Agente adequado recupere o passo ou execute a ação corretiva adequada (tal pode envolver a modificação do estado de um passo). Tenha em atenção que as ações de recuperação ou corretivas são implementadas pelo Scheduler e pelos Agentes. O Supervisor simplesmente deve pedir que estas ações sejam realizadas.
O Scheduler, o Agente e o Supervisor são componentes lógicos e a implementação física deles depende da tecnologia que está a ser utilizada. Por exemplo, vários agentes lógicos podem ser implementados como parte de um serviço Web único.
O Scheduler mantém informações sobre o progresso da tarefa e o estado de cada passo num arquivo de dados durável, denominado arquivo de estado. O Supervisor pode utilizar estas informações para ajudar a determinar se um passo falhou. A figura mostra a relação entre o Scheduler, os Agentes, o Supervisor e o arquivo de estado.
Nota
Este diagrama mostra uma versão simplificada do padrão. Numa implementação real, podem existir muitas instâncias do Scheduler em execução em simultâneo, cada uma delas um subconjunto de tarefas. Da mesma forma, o sistema pode executar várias instâncias de cada Agente ou mesmo de vários Supervisores. Neste caso, os supervisores devem coordenar cuidadosamente o seu trabalho uns com os outros para garantir que não competem para recuperar os mesmos passos e tarefas falhados. O padrão de Eleição de Coordenador fornece uma solução possível para este problema.
Quando a aplicação está pronta para executar uma tarefa, submete um pedido ao Scheduler. O Scheduler regista as informações de estado iniciais da tarefa e dos passos (por exemplo, passo ainda não iniciado) no arquivo de estado e, em seguida, começa a realizar as operações definidas pelo fluxo de trabalho. À medida que o Scheduler inicia cada passo, atualiza as informações sobre o estado desse passo no arquivo de estado (por exemplo, passo em execução).
Se um passo fizer referência a um serviço ou recurso remoto, o Scheduler enviará uma mensagem ao Agente adequado. A mensagem contém as informações que o Agente precisa de transmitir ao serviço ou das quais precisa para aceder ao recurso, para além do tempo de conclusão da operação. Se o Agente concluir a operação com sucesso, devolverá uma resposta ao Scheduler. Assim, o Scheduler pode atualizar as informações de estado no arquivo de estado (por exemplo, passo concluído) e executar o passo seguinte. Este processo continua até que toda a tarefa seja concluída.
Um Agente pode implementar qualquer lógica de repetição necessária para realizar o trabalho. No entanto, se o Agente não concluir o trabalho antes de o período de conclusão expirar, o Scheduler assumirá que a operação falhou. Neste caso, o Agente deve parar o trabalho e não tentar devolver nada ao Scheduler (nem mesmo uma mensagem de erro) ou tentar qualquer outra forma de recuperação. O motivo para esta restrição é que, depois de um passo ter excedido o tempo limite ou ter falhado, outra instância do Agente pode ser agendada para executar a etapa falhada (este processo é descrito mais à frente).
Se o Agente falhar, o Scheduler não receberá nenhuma resposta. O padrão não faz uma distinção entre um passo que excedeu o tempo limite e um que falhou genuinamente.
Se um passo exceder o limite de tempo ou falhar, o arquivo de estado conterá um registo que indica que o passo está em execução, mas o tempo de conclusão será ultrapassado. O Supervisor procura passos como este e tenta recuperá-los. Uma estratégia possível é que o Supervisor atualize o valor complete-by para estender o tempo disponível para concluir a etapa e, em seguida, envie uma mensagem para o Agendador identificando a etapa que atingiu o tempo limite. O Agendador pode então tentar repetir esta etapa. No entanto, este design requer que as tarefas sejam idempotentes. O sistema deve conter infraestruturas para manter a coerência. Para obter mais informações, consulte Infraestrutura repetível, Arquiteto de aplicativos do Azure para resiliência e disponibilidade e Guia de decisão de consistência de recursos.
O Supervisor pode precisar evitar que a mesma etapa seja repetida se ela falhar continuamente ou atingir o tempo limite. Para fazer isso, o supervisor poderia manter uma contagem de tentativas para cada etapa, juntamente com as informações do estado, no armazenamento do estado. Se esta contagem exceder um limiar predefinido, o Supervisor poderá adotar uma estratégia de espera por um período prolongado antes de notificar o Scheduler, que deve repetir o passo, na expectativa de que as falhas serem resolvidas durante este período. Em alternativa, o Supervisor pode enviar uma mensagem ao Scheduler para pedir que a tarefa completa seja anulada ao implementar um padrão de Transação de Compensação. Esta abordagem implicará que o Scheduler e os Agentes forneçam as informações necessárias para implementar as operações de compensação para cada passo concluído com sucesso.
O Supervisor não tem como objetivo monitorizar o Scheduler nem os Agentes, nem reiniciá-los em caso de falha. Este aspeto do sistema deve ser processado pela infraestrutura que estes componentes estão a executar. Da mesma forma, o Supervisor não deve ter conhecimento das operações empresariais reais que as tarefas a serem realizadas pelo Scheduler estão a executar (incluindo como compensar caso estas tarefas falhem). Este é o objetivo da lógica do fluxo de trabalho implementado pelo Scheduler. A competência exclusiva do Supervisor consiste em determinar se um passo falhou e providenciar para que seja repetido ou para que toda a tarefa que contém o passo falhado seja anulada.
Se o Scheduler for reiniciado após uma falha ou se o fluxo de trabalho a ser realizado pelo Scheduler terminar inesperadamente, o Scheduler deverá conseguir determinar o estado de qualquer tarefa em utilização que estava a processar quando falhou e estar preparado para retomar a mesma a partir desse ponto. É provável que os detalhes de implementação deste processo sejam específicos do sistema. Se a tarefa não puder ser recuperada, poderá ser necessário anular o trabalho já realizado pela tarefa. A implementação de uma transação de compensação poderá também ser necessária.
A vantagem principal deste padrão é que o sistema é resiliente em caso de falhas inesperadas, temporárias ou irrecuperáveis. O sistema pode ser construído para ser auto-curativo. Por exemplo, se um Agente ou o Scheduler falharem, poderá iniciar um novo agente e o Supervisor poderá fazer com que uma tarefa seja retomada. Se o Supervisor falhar, outra instância poderá ser iniciada e assumir a partir do ponto onde ocorreu a falha. Se o Supervisor estiver agendado para ser executado periodicamente, uma nova instância poderá ser iniciada automaticamente após um intervalo predefinido. O arquivo de estado pode ser replicado para alcançar um maior grau de resiliência.
Problemas e considerações
Deve considerar os seguintes pontos ao decidir como implementar este padrão:
Este padrão pode ser difícil de implementar e necessita de testes rigorosos de todos os modos de falha possíveis do sistema.
A lógica de recuperação/repetição implementada pelo Scheduler é complexa e depende das informações de estado contidas no arquivo de estado. Também pode ser preciso registar as informações necessárias para implementar uma transação de compensação num arquivo de dados durável. Uma transação de compensação também pode falhar.
A frequência com que o Supervisor é executado será importante. Deve ser executado com frequência suficiente para impedir que quaisquer passos falhados bloqueiem uma aplicação durante um período prolongado, mas não deve ser executado de uma forma tão frequente que se torne um custo.
Os passos realizados por um Agente podem ser executados mais do que uma vez. A lógica que implementa estes passos deve ser idempotente.
Quando utilizar este padrão
Utilize este padrão quando um processo a ser executado num ambiente distribuído, tal como a cloud, tem de ser resilientes a falhas de comunicações e/ou falhas operacionais.
Este padrão pode não ser adequado para tarefas que não invocam serviços remotos ou recursos de acesso remotos.
Design da carga de trabalho
Um arquiteto deve avaliar como o padrão Scheduler Agent Supervisor pode ser usado no design de sua carga de trabalho para abordar as metas e os princípios abordados nos pilares do Azure Well-Architected Framework. Por exemplo:
Pilar | Como esse padrão suporta os objetivos do pilar |
---|---|
As decisões de projeto de confiabilidade ajudam sua carga de trabalho a se tornar resiliente ao mau funcionamento e a garantir que ela se recupere para um estado totalmente funcional após a ocorrência de uma falha. | Esse padrão usa métricas de integridade para detetar falhas e redirecionar tarefas para um agente íntegro, a fim de mitigar os efeitos de um mau funcionamento. - RE:05 Redundância - RE:07 Auto-cura |
A Eficiência de Desempenho ajuda sua carga de trabalho a atender às demandas de forma eficiente por meio de otimizações em escala, dados e código. | Esse padrão usa métricas de desempenho e capacidade para detetar a utilização atual e encaminhar tarefas para um agente com capacidade. Você também pode usá-lo para priorizar a execução de trabalhos de prioridade mais alta sobre trabalhos de prioridade mais baixa. - PE:05 Dimensionamento e particionamento - PE:09 Fluxos críticos |
Como em qualquer decisão de design, considere quaisquer compensações em relação aos objetivos dos outros pilares que possam ser introduzidos com esse padrão.
Exemplo
Uma aplicação Web que implementa um sistema de comércio eletrónico foi implementada no Microsoft Azure. Os utilizadores podem executar esta aplicação para procurar os produtos disponíveis e realizar encomendas. A interface de utilizador é executada como uma função da Web e os elementos de processamento das encomendas da aplicação são implementados como um conjunto de funções de trabalho. Parte da lógica de processamento da encomenda envolve o acesso a um serviço remoto, podendo este aspeto do sistema ser suscetível a falhas transitórias ou mais duradouras. Por este motivo, os estruturadores utilizaram o padrão do Supervisor de Agente do Scheduler para implementar os elementos de processamento da encomenda do sistema.
Quando um cliente realiza uma encomenda, a aplicação constrói uma mensagem que descreve a encomenda e publica esta mensagem numa fila. Um processo de submissão separado, em execução numa função de trabalho, obtém a mensagem, insere os detalhes da encomenda na base de dados de encomendas e cria um registo para o processamento da encomenda no arquivo de estado. Tenha em atenção que as inserções na base de dados das encomendas e o arquivo de estado são realizados como parte da mesma operação. O processo de submissão foi concebido para garantir que ambas as inserções são concluídas em conjunto.
As informações de estado criadas pelo processo de submissão para a encomenda incluem:
OrderID. O ID da encomenda na base de dados de encomendas.
LockedBy. O ID da instância da função de trabalho a processar a encomenda. Podem existir várias instâncias atuais da função de trabalho a executar o Scheduler, mas cada encomenda só deve ser processada por uma única instância.
CompleteBy. A hora em que a encomenda deve ser processada.
ProcessState. O estado atual da tarefa a processar a encomenda. Os Estados possíveis são:
- Pendente. A encomenda foi criada, mas o processamento ainda não foi iniciado.
- Em processamento. A encomenda está atualmente a ser processada.
- Processada. A encomenda foi processada com sucesso.
- Error. O processamento da encomenda falhou.
FailureCount. O número de vezes que o processamento da encomenda foi tentado.
Nestas informações de estado, o campo OrderID
é copiado do ID da encomenda da nova encomenda. Os campos LockedBy
e CompleteBy
estão definidos como null
, o campo ProcessState
está definido como Pending
e o campo FailureCount
está definido como 0.
Nota
Neste exemplo, a lógica de processamento de encomendas é relativamente simples e tem apenas um único passo que invoca um serviço remoto. Em um cenário de várias etapas mais complexo, o processo de envio provavelmente envolveria várias etapas e, portanto, vários registros seriam criados no armazenamento de estado — cada um descrevendo o estado de uma etapa individual.
O Scheduler também é executado como parte de uma função de trabalho e implementa a lógica de negócio que processa a encomenda. Uma instância do Scheduler a consultar as encomendas examina o arquivo de estado para os registos em que o campo LockedBy
é nulo e o campo ProcessState
está pendente. Quando o Scheduler encontra uma nova encomenda, preenche imediatamente o campo LockedBy
com o seu próprio ID de instância, define o campo CompleteBy
para um tempo adequado e define o campo ProcessState
para processamento. O código foi concebido para ser exclusivo e atómico para garantir que duas instâncias em simultâneo do Scheduler não possam processar a mesma encomenda ao mesmo tempo.
Em seguida, o Scheduler executa o fluxo de trabalho comercial para processar a encomenda de forma assíncrona e transmite o valor do campo OrderID
a partir do arquivo de estado. O fluxo de trabalho a processar a encomenda obtém os detalhes da encomenda da base de dados de encomendas e executa o trabalho. Quando um passo no fluxo de trabalho de processamento da encomenda tem de invocar o serviço remoto, utiliza um Agente. O passo do fluxo de trabalho comunica com o Agente através de um par de filas de mensagens do Azure Service Bus a funcionarem como um canal de pedido/resposta. A figura mostra uma visão de alto nível da solução.
A mensagem enviada ao Agente por um passo do fluxo de trabalho descreve a encomenda e inclui o tempo de conclusão. Se o Agente receber uma resposta do serviço remoto antes de o tempo de conclusão expirar, este publicará uma mensagem de resposta na fila do Service Bus no qual o fluxo de trabalho está a escutar. Quando a etapa do fluxo de trabalho recebe a mensagem de resposta válida, ela conclui seu processamento e o Agendador define o ProcessState
campo do estado do pedido como processado. O processamento da encomenda foi concluído com sucesso.
Se o tempo de conclusão expirar antes de o Agente receber uma resposta do serviço remoto, o Agente simplesmente parará o processamento e terminará o tratamento da encomenda. Da mesma forma, se o fluxo de trabalho a processar a encomenda exceder o tempo de conclusão, este também terminará. Em ambos os casos, o estado da encomenda no arquivo de estado permanece definido como “Em processamento”, mas o tempo de conclusão indica que o tempo de processamento da encomenda foi ultrapassado e o processo é considerado como tendo falhado. Tenha em atenção que, se o Agente que está a aceder ao serviço remoto ou o fluxo de trabalho que está a processar a encomenda (ou ambos) terminar inesperadamente, as informações no arquivo de estado permanecerão definidas como “Em processamento” e, eventualmente, terão um valor de conclusão expirado.
Se o Agente detetar uma falha irrecuperável não transitória enquanto está a tentar contactar o serviço remoto, este poderá enviar uma resposta de erro de volta para o fluxo de trabalho. O Scheduler pode definir o estado da encomenda como Erro e gerar um evento que alerta um operador. O operador pode, em seguida, tentar resolver manualmente o motivo da falha e submeter novamente o passo de processamento falhado.
O Supervisor examina periodicamente o arquivo de estado ao procurar as encomendas com um valor de conclusão expirado. Se o Supervisor encontrar um registo, incrementará o campo FailureCount
. Se o valor de contagem de falhas for inferior a um valor de limiar especificado, o Supervisor reporá o campo LockedBy
como nulo, atualizará o campo CompleteBy
com um novo prazo de expiração e definirá o campo ProcessState
como pendente. Uma instância do Scheduler pode recuperar esta encomenda e proceder ao seu processamento tal como anteriormente. Se o valor de contagem de falhas exceder um limiar especificado, assume-se que o motivo da falha se deve a não ser transitório. O Supervisor define o estado da encomenda como Erro e gera um evento que alerta um operador.
Neste exemplo, o Supervisor é implementado numa função de trabalho separada. Pode utilizar várias estratégias para que a tarefa do Supervisor seja executada, incluindo a utilização do serviço do Scheduler do Azure (não deve ser confundido com o componente do programador neste padrão). Para obter mais informações sobre o serviço do Scheduler do Azure, consulte a página Scheduler.
Apesar de não ser apresentado neste exemplo, o Scheduler pode ter de manter a aplicação que submeteu a encomenda informada sobre o progresso e o estado da encomenda. A aplicação e o Scheduler estão isolados um do outro para eliminar qualquer dependência entre ambos. A aplicação não tem conhecimento sobre qual a instância do Scheduler que está a processar a encomenda nem o Scheduler tem conhecimento de qual a instância específica da aplicação que publicou a encomenda.
Para permitir que o estado da encomenda seja comunicado, a aplicação pode utilizar a sua própria fila de respostas privada. Os detalhes desta fila de respostas são incluídos como parte do pedido enviado para o processo de submissão, que inclui estas informações no arquivo de estado. Em seguida, o Scheduler publica as mensagens nesta fila, indicando o estado da encomenda (pedido recebido, encomenda concluída, encomenda falhada, entre outros). O ID da encomenda deve ser incluído nestas mensagens, para que possa ser correlacionado com o pedido original enviado pela aplicação.
Próximos passos
As seguintes orientações também podem ser relevantes ao implementar este padrão:
Asynchronous Messaging Primer (Manual Básico de Mensagens Assíncronas). Normalmente, os componentes no padrão do Supervisor de Agente do Scheduler são executados desacoplados uns dos outros e comunicam de forma assíncrona. Descreve algumas das abordagens que podem ser utilizadas para implementar comunicações assíncronas com base nas filas de mensagens.
Reference 6: A Saga on Sagas (Referência 6: uma saga nas sagas). Um exemplo mostra como o padrão CQRS utiliza um gestor de processos (parte das orientações do Percurso CQRS).
Recursos relacionados
Os seguintes padrões também podem ser relevantes ao implementar esse padrão:
Padrão Repetição. Um agente pode utilizar este padrão para repetir de forma transparente uma operação que acede a um serviço ou a recurso remotos que tenham falhado anteriormente. Utilize quando a causa da falha é considerada como transitória e pode ser corrigida.
Padrão Disjuntor Automático. Um Agente pode utilizar este padrão para processar falhas que demoram um período de tempo a corrigir ao ligar a um serviço ou recurso remotos variáveis.
Padrão Transação de Compensação. Se o fluxo de trabalho a ser realizado por um Scheduler não puder ser concluído com sucesso, poderá ser necessário anular todo o trabalho que foi executado anteriormente. O padrão de Transação de Compensação descreve a forma como isto pode ser obtido para operações que seguem o modelo de consistência eventual. Estes tipos de operações são normalmente implementados por um Scheduler que realiza processos e fluxos de trabalho empresariais complexos.
Padrão de Eleição de Coordenador. Pode ser necessário coordenar as ações de várias instâncias de um Supervisor para impedir que estas tentem recuperar o mesmo processo falhado. O padrão de Eleição de Coordenador descreve como fazê-lo.
Cloud Architecture: O padrão Scheduler-Agent-Supervisor no blog de Clemens Vasters