AWS
April 4, 2024

Corrigindo o AWS Step Functions com referências inativadas de Job Definitions no AWS Batch

Descrição do Problema

Na Tenchi Security, utilizamos o AWS Batch juntamente com o AWS Step Functions para executar testes de segurança em escala em nosso produto Zanshin. Esta abordagem faz parte de nossa estratégia para ter uma stack sem servidor, como discutido neste artigo anterior.

O AWS Batch permite executar tarefas de processamento em grande escala sem a necessidade de provisionar, gerenciar ou dimensionar manualmente servidores e o AWS Step Functions oferece uma maneira de orquestrar microserviços, aplicativos sem servidor e fluxos de trabalho de contêiner facilmente e de forma visual.

Nós, assim como muitas empresas, utilizamos o AWS Batch para executar tarefas baseadas em contêineres em Step Functions em escala. No entanto, um problema surge quando você utiliza esses serviços juntos em um ambiente dinâmico como o nosso, onde múltiplas execuções e alterações no código ocorrem frequentemente e são gerenciadas usando o CloudFormation. O problema ocorre quando novas versões de um Job Definition (Definição de Trabalho) no AWS Batch são implantadas enquanto um Step Function que a utiliza está em execução.

Especificamente, se uma task do Step Function for iniciada momentos antes de uma nova implantação de um Job Definition, ela pode falhar com a seguinte mensagem de erro:

Isso ocorre porque quando o CloudFormation atualiza um Job Definition, ele não apenas cria uma nova revisão, mas também marca todas as revisões anteriores como inativas. Esta inativação faz com que as execuções em andamento que dependem de revisões anteriores falhem, como no exemplo acima.

Este é um “problema” do CloudFormation que é conhecido há anos. Tenha em mente que isso também afeta outros sistemas ou estruturas que dependem ou são construídos com base no CloudFormation, como o Serverless Framework ou o CDK.

Em nosso caso, isso resultou em falhas de verificações de segurança em execução por longos períodos e precisando ser re-executadas com uma tarefa do Step Function atualizada que referencia a nova revisão do Job Definition. Os impactos foram sentidos pelos clientes que tiveram que esperar mais tempo para que os resultados fossem disponibilizados e houve um aumento nos custos devido às execuções duplicadas dos passos de verificação.

Solução Paliativa

Até o momento de escrita deste post, a AWS não tem uma solução para a causa raiz desse problema. Idealmente, o CloudFormation deveria ter uma opção para manter as revisões existentes ativas quando uma nova é criada. Em um contato recente com o suporte da AWS, eles mencionaram que existe uma issue para isso no roadmap do CloudFormation, mas não puderam fornecer uma data-alvo para sua implementação. Preocupantemente, até o momento, isso ainda não foi atribuído a nenhuma pessoa ou projeto no repositório do roadmap no GitHub.

A solução alternativa para este problema envolve não depender de novas revisões, mas sim criar novos Job Definitions a cada alteração e manter os anteriores enquanto forem necessários.

Para garantir que cada novo Job Definition seja único e não entre em conflito com versões anteriores, podemos anexar um carimbo de data e hora ou qualquer coisa que seja atualizada a cada alteração (tag da imagem do contêiner, versão da aplicação, etc.) ao nome do Job Definition. Essa abordagem permite a criação sem conflitos e facilita o gerenciamento de versões no ambiente.

Fazemos isso aplicando estrategicamente as propriedades DeletionPolicy: Retain e UpdateReplacePolicy: Retain. Essas propriedades garantem que, ao atualizar o Job Definition, a versão anterior seja preservada em vez de excluída, enquanto o novo job definition é criado com um nome diferente.

Em nosso cenário, optamos por utilizar a tag da imagem do docker como o sufixo. Essa escolha garante que novos Job Definitions sejam criados exclusivamente quando a versão da imagem do contêiner é atualizada. Se a versão da imagem permanecer inalterada, não haverá diferença no nome do Job Definition.

No entanto, essa abordagem necessita de atenção, pois os antigos Job Definitions nunca seriam excluídos podendo gerar problemas desnecessários e até mesmo criar um impacto se a AWS passasse a impor um limite no número de Definições de Tarefa por conta ou região.

Exemplo de um Template CloudFormation para um Job Definition

Temos aqui um exemplo simples de um template do CloudFormation que ilustra a criação de um Job Definition com a solução paliativa mencionada. De forma simplista, anexamos um carimbo de data e hora ao nome do Job Definition.

Essa abordagem garante que cada implantação crie um novo Job Definition, mantendo o ambiente estável evitando erros de execução relacionados aos status de revisão.

Como resultado, em nosso exemplo, teremos dois Job Definitions ativos com o mesmo prefixo de nome, mas com carimbos de data e hora diferentes. Cada um está associado a uma versão diferente da imagem do contêiner.

A imagem abaixo mostra a State Machine usando a revisão 1 do Job Definition “my-jobdefinition-dev-20240313-081021”.

Após atualizar a stack, a mesma State Machine agora está usando a revisão 1 do Job Definition “my-jobdefinition-dev-20240314-081021”.

Observa-se que o número da revisão é sempre :1, devido à criação constante de novos job definitions, evitando a perda de referências para revisões desativadas.

Quanto à automação para limpar os antigos Job Definitions, utilizamos a fase de post build que é executada na pipeline e roda um script específico de limpeza. Ele verifica os Job Definitions ativos relacionados ao serviço sendo implantado e analisa a tag de carimbo de data e hora. Ele se certifica de manter os dois últimos Job Definition, além de quaisquer outros criados nas últimas 24 horas (já que nossos jobs não duram mais do que isso). Em seguida, procede à exclusão de quaisquer outros Job Definition mais antigos.

Esta solução alternativa mitiga erros no Step Functions ao implementar novas versões do Job Definition. Embora a AWS não ofereça uma solução oficial para este caso específico, esta parece ser a melhor solução alternativa. É importante observar que será necessário limpar o ambiente para realmente desativar os Job Definitions não utilizados.

Definition

Luis F. Pontes