Artigo
· Abr. 4, 2023 13min de leitura

Entrega contínua de sua solução InterSystems usando GitLab – Parte XI: Interoperabilidade

Bem-vindo ao capítulo seguinte da minha série sobre CI/CD, onde discuto possíveis abordagens de desenvolvimento de software com tecnologias da InterSystems e GitLab.

Hoje, vamos falar sobre interoperabilidade.

Problema

Em uma produção de interoperabilidade ativa, há dois fluxos de processo separados: uma produção em funcionamento que processa as mensagens e um fluxo de processo CI/CD que atualiza o código, a configuração da produção e as configurações padrão do sistema.

Claramente, os processos CI/CD afetam a interoperabilidade. No entanto, as perguntas são:

  • O que acontece exatamente durante uma atualização?
  • O que precisamos fazer para minimizar ou eliminar o tempo de inatividade da produção durante uma atualização?

Terminologia

  • Host de Negócio (Business Host - BH) - um elemento configurável da Produção da Interoperabilidade: Serviço de Negócio (Business Service - BS), Processo de Negócio ( Business Process - BP, BPL) ou Operação de Negócio (Business Operation, BO).
  • Job do Host de Negócio (Business Host Job) - job do InterSystems IRIS que executa o código do Host de Negócio e é gerenciado pela produção de interoperabilidade.
  • Produção - coleção interconectada de Hosts de Negócio.
  • Configurações Padrão do Sistema (System Default Settings - SDS) - valores específicos do ambiente de instalação do InterSystems IRIS.
  • Mensagem Ativa - uma solicitação que está sendo processada por um Job do Host de Negócio. Um Job do Host de Negócio só pode ter uma Mensagem Ativa. O Job do Host de Negócio que não tem uma Mensagem Ativa está inativo.

O que está acontecendo?

Vamos começar com o ciclo de vida da produção.

Início da Produção

Primeiro, a Produção pode ser iniciada. Só pode ser executada uma produção por namespace ao mesmo tempo, e em geral (a menos que você saiba o que e porque está fazendo isso), apenas uma produção deve ser executada por namespace. Alternar várias vezes em um namespace entre duas ou mais produções diferentes não é recomendado. Ao iniciar a produção, todos os Hosts de Negócio habilitados definidos nela são inicializados. Se alguns Hosts de Negócio não inicializarem, isso não afeta a inicialização da Produção.

Dicas:

  • Comece a produção no Portal de Gerenciamento de Sistemas ou ao chamar: ##class(Ens.Director).StartProduction("ProductionName")
  • Execute código arbitrário na inicialização da Produção (antes que qualquer Job do Host de Negócio seja inicializado) ao implementar um método OnStart
  • A inicialização da Produção é um evento auditável. Você sempre pode ver quem e quando fez o que no Log de Auditoria.

Atualização da Produção

Após a inicialização da Produção, Ens.Director monitora continuamente a produção em execução. Há dois estados de produção: o estado desejado, definido na classe da produção e nas Configurações Padrão do Sistema, e o estado em execução, os jobs atualmente em execução com configurações aplicadas quando os jobs foram criados. Se os estados desejado e atual forem idênticos, está tudo bem, mas a produção pode (e deve) ser atualizada se houver uma diferença. Geramente, você vê isso como um botão vermelho Update na página de Configurações da Produção no Portal de Gerenciamento de Sistemas.

A atualização da produção significa uma tentativa de corresponder o estado atual da Produção ao estado visado.

A execução de ##class(Ens.Director).UpdateProduction(timeout=10, force=0) para atualizar a produção faz o seguinte com cada Host de Negócio:

  1. Compara as configurações ativas às configurações de produção/SDS/classe
  2. Se, e apenas se, (1) apresentar uma discrepância, o Host de Negócio será marcado como desatualizado, exigindo uma atualização.

Depois de executar isso para cada Host de Negócio, UpdateProduction cria o conjunto de mudanças:

  • Hosts de Negócio para interromper
  • Hosts de Negócio para inicializar
  • Configurações da produção para atualizar

E, depois disso, aplica essas mudanças.

Dessa forma, "atualizar" as configurações sem mudar nada resulta em nenhum tempo de inatividade da produção.

Dicas:

  • Atualize a produção no Portal de Gerenciamento de Sistemas ou ao chamar: ##class(Ens.Director).UpdateProduction(timeout=10, force=0)
  • O tempo limite de atualização padrão do Portal de Gerenciamento de Sistemas é 10 segundos. Se você sabe que o processamento das mensagens leva mais do que isso, chame Ens.Director:UpdateProduction com um tempo limite maior.
  • O tempo limite da atualização é uma configuração da produção, e você pode mudar para um valor maior. Essa configuração se aplica ao Portal de Gerenciamento de Sistemas.

Atualização do código

UpdateProduction NÃO ATUALIZA BHs com código desatualizado. Esse é um comportamento voltado para a segurança, mas, se você quiser atualizar todos os BHs em execução automaticamente se o código subjacente mudar, siga estas etapas:

Primeiro, carregue e compile desta maneira:

do $system.OBJ.LoadDir(dir, "", .err, 1, .load)
do $system.OBJ.CompileList(load, "curk", .errCompile, .listCompiled)

Agora, listCompiled teria todos os itens que foram realmente compilados (use git diffs para minimizar o conjunto carregado) devido à flag u. Use listCompiled para obter um $lb de todas as classes que foram compiladas:

set classList = ""
set class = $o(listCompiled(""))
while class'="" { 
  set classList = classList _ $lb($p(class, ".", 1, *-1))
  set class=$o(listCompiled(class))
}

Depois disso, calcule uma lista de BHs que precisam de uma reinicialização:

SELECT %DLIST(Name) bhList
FROM Ens_Config.Item 
WHERE 1=1
  AND Enabled = 1
  AND Production = :production
  AND ClassName %INLIST :classList

Por fim, após obter bhList, interrompa e inicie os hosts afetados:

for stop = 1, 0 {
  for i=1:1:$ll(bhList) {
    set host = $lg(bhList, i)
    set sc = ##class(Ens.Director).TempStopConfigItem(host, stop, 0)
  }
  set sc = ##class(Ens.Director).UpdateProduction()
}

Interrupção da produção

As produções podem ser interrompidas, ou seja, uma solicitação pode ser enviada para desativar todos os Jobs do Host de Negócio (com segurança, após lidarem com as mensagens ativas, se houver alguma).

Dicas:

  • Interrompa a produção no Portal de Gerenciamento de Sistemas ou ao chamar: ##class(Ens.Director).StopProduction(timeout=10, force=0)
  • O tempo limite de interrupção padrão do Portal de Gerenciamento de Sistemas é 120 segundos. Se você sabe que o processamento das mensagens leva mais do que isso, chame Ens.Director:StopProduction com um tempo limite maior.
  • O tempo limite de interrupção é uma configuração da produção. Você pode alterar isso para um valor maior. Essa configuração se aplica ao Portal de Gerenciamento de Sistemas.
  • Execute código arbitrário na interrupção da produção ao implementar um método OnStart
  • A interrupção da produção é um evento auditável. Você sempre pode ver quem e quando fez o que no Log de Auditoria.

O importante aqui é que a produção seja a soma total dos Hosts de Negócio:

  • Ao iniciar a produção, todos os Hosts de Negócio habilitados são inicializados.
  • A interrupção da produção também interrompe todos os Hosts de Negócio em execução.
  • A atualização da produção significa calcular um subconjunto de Hosts de Negócio que estão desatualizados, para que sejam interrompidos e, imediatamente depois disso, inicializados novamente. Além disso, um Host de Negócio recém-adicionado é inicializado, e um Host de Negócio excluído da produção é interrompido.

Isso nos leva ao ciclo de vida dos Hosts de Negócio.

Inicialização do Host de Negócio

Os Hosts de Negócio são compostos de Jobs de Hosts de Negócio idênticos (de acordo com um valor de configuração de tamanho do pool). Ao inicializar um Host de Negócio, todos os Jobs de Hosts de Negócio também são inicializados. Eles são inicializados em paralelo.

Jobs de Host de Negócio individuais são inicializados desta maneira:

  1. A interoperabilidade define como job um novo processo que se tornaria um Job de Host de Negócio.
  2. O novo processo é registrado como um job de interoperabilidade.
  3. O código de Host de Negócio e o código do Adapter são carregados na memória do processo.
  4. As configurações relacionadas a um Host de Negócio e Adapter são carregadas na memória. A ordem de precedência é: a. Configurações da Produção (substituem as Configurações de Classe e Padrão do Sistema). b. Configurações Padrão do Sistema (substituem as Configurações de Classe). c. Configurações de classe.
  5. O job está pronto e começa a aceitar mensagens.

Após a conclusão de (4), o Job não pode alterar as configurações ou o código, então quando você importa código novo/igual e configurações padrão do sistema novas/iguais, isso não afeta os jobs de interoperabilidade atualmente em execução.

Interrupção do Hosts de Negócio

Interromper um Job de Host de Negócio significa o seguinte:

  1. A interoperabilidade pede que o Job pare de aceitar mensagens/entradas.
  2. Se houver uma mensagem ativa, o Job de Host de Negócio tem segundos de tempo limite para processar (ao concluir, finalizando o método OnMessage para BO, OnProcessInput para BS, S<int> para BPL BPs e On* para BPs).
  3. Se uma mensagem ativa não for processada até o tempo limite e force=0, ocorrerá a falha da atualização da produção para esse Host de Negócio (voce verá um botão "Update" vermelho no Portal de Gerenciamento de Sistemas).
  4. A interrupção é bem-sucedida se algo nesta lista for verdadeiro:
    • Nenhuma mensagem ativa
    • A mensagem ativa foi processada antes de timeout
    • A mensagem ativa não foi processada antes do tempo limite, MAS force=1
  5. O job é cancelado com interoperabilidade e é interrompido.

Atualização do Host de Negócio

A atualização do Host de Negócio significa a interrupção de todos os Jobs em execução para o Host de Negócio e a inicialização de novos Jobs.

Regras de negócios, de roteamento e DTLs

Todos os Hosts de Negócio são inicializados imediatamente usando as novas versões das Regras de negócios, de roteamento e DTLs assim que ficarem disponíveis. A reinicialização de um Host de Negócio não é necessária nesse caso.

Atualizações offline

Às vezes, no entanto, as atualizações da produção exigem tempo de inatividade de Hosts de Negócio individuais.

Regras dependem de novo código

Considere a situação. Você tem uma Regra de Roteamento X atual que encaminha as mensagens para o Processo de Negócio A ou B com base em critérios arbitrários. Em um novo commit, você adiciona, simultaneamente:

  • Processo de Negócio C
  • Uma nova versão da Regra de Roteamento X, que encaminha mensagens para A, B ou C.

Nesse caso, você não pode só carregar a regra primeiro e depois atualizar a produção. A regra recém-copilada imediatamente começaria a encaminhar as mensagens para o Processo de Negócio C, que o InterSystems IRIS talvez ainda não tenha compilado ou a interoperabilidade ainda não tenha atualizado para usar. Nesse caso, você precisa desativar o Host de Negócio com uma Regra de Roteamento, atualizar o código, atualizar a produção e ativar o Host de Negócio novamente.

Observações:

  • Se você atualizar uma produção usando um arquivo de implantação de produção, todos os BHs afetados são desativados/ativados automaticamente.
  • Para hosts invocados InProc, a compilação invalida o cache de um host específico mantido pelo autor da chamada.

Dependências entre Hosts de Negócio

As dependências entre Hosts de Negócio são fundamentais. Suponha que você tenha os Processos de Negócio A e B, em que A envia mensagens a B. Em um novo commit, você adiciona, simultaneamente:

  • Uma nova versão do Processo A, que define uma nova propriedade X em uma solicitação para B
  • Uma nova versão do Processo B que pode processar uma nova propriedade X

Nesse caso, PRECISAMOS atualizar o Processo B primeiro e o A depois. Você pode fazer isso de uma das seguintes maneiras:

  • Desativar Hosts de Negócio durante a atualização
  • Divida a atualização em duas partes: primeiro, atualize apenas o Processo B e, depois, em uma atualização separada, comece a enviar mensagens para ele do Processo A.

Uma variação mais desafiadora desse tema, em que as novas versões dos Processos A e B são incompatíveis com as versões antigas, exige tempo de inatividade do Host de Negócio.

Filas

Se você sabe que, após a atualização, um Host de Negócio não conseguirá processar mensagens antigas, você precisa garantir que a Fila do Host de Negócio esteja vazia antes da atualização. Para isso, desative todos os Hosts de Negócio que enviam mensagens para o Host de Negócios e espere até que a fila fique vazia.

Mudança de estado nos Processos de Negócio BPL

Primeiro, uma pequena introdução sobre como funcionam os BPs do BPL. Depois de compilar um BP do BPL, duas classes são criadas no pacote com o mesmo nome que o da classe BPL completa:

  • A classe Thread1 contém os métodos S1, S2, ... SN, que corresponde às atividades no BPL
  • A classe Context tem todas as variáveis de contexto, além do próximo estado que o BPL executaria (ou seja, S5)

Além disso, a classe BPL é persistente e armazena as solicitações que estão sendo processadas.

O BPL funciona ao executar os métodos S em uma classe Thread e atualizando de maneira correspondente a tabela da classe BPL, Context e Thread1, em que uma mensagem "em processamento" é uma linha em uma tabela BPL. Após o processamento da solicitação, o BPL exclui as entradas do BPL, Context e Thread. Como os BPs do BPL são assíncronos, um job BPL pode processar simultaneamente várias solicitações ao salvar as informações entre chamadas S e alternar entre diferentes solicitações. Por exemplo, o BPL processou uma solicitação até chegar a uma atividade sync, aguardando uma resposta da BO. Ele salvaria o contexto atual no disco, com a propriedade %NextState (na classe Thread1) definida para o método S de atividade de resposta e trabalharia em outras solicitações até a BO responder. Após a resposta da BO, o BPL carregaria "Context" na memória e executaria o método correspondente a um estado salvo na propriedade %NextState.

Agora, o que acontece quando atualizamos o BPL? Primeiro, precisamos conferir se pelo menos uma destas condições é atendida:

  • Durante a atualização, a tabela Context está vazia, o que significa que nenhuma mensagem ativa está em trabalho.
  • Os Novos Estados são os mesmos que os antigos ou os novos Estados são adicionados após os antigos.

Se pelo menos uma condição for atendida, podemos continuar. Não há solicitações de pré-atualização para processar o BPL pós-atualização ou os Estados são adicionados no final, o que significa que as solicitações antigas também podem ir para lá (supondo que as solicitações de pré-atualização sejam compatíveis com as atividades e o processamento do BPL pós-atualização).

Mas e se você tiver solicitações ativas em processamento e o BPL mudar a ordem dos estados? O ideal é, se você puder esperar, desativar os autores de chamada do BPL e esperar até que a fila esteja vazia. Valide se a tabela Context também está vazia. Lembre-se de que a Fila mostra apenas as solicitações não processadas e a tabela Context armazena as solicitações em trabalho, então um BPL muito ocupado pode mostrar o tamanho da Fila como zero e isso é normal. Depois disso, desative o BPL, realize a atualização e ative todos os Hosts de Negócio desativados anteriormente.

Se isso não for possível (geralmente quando o BPL é muito longo, lembro de atualizar um que demorou cerca de uma semana para processar uma solicitação, ou a janela de atualização é muito curta), use o versionamento do BPL.

Como alternativa, você pode escrever um script de atualização. No script de atualização, mapeie os próximos estados antigos para os próximos estados novos e execute na tabela Thread1 para que o BPL atualizado possa processar solicitações antigas. O BPL precisa ser desativado durante a atualização. Dito isso, é uma situação extremamente rara e geralmente desnecessária, mas, se precisar fazer isso, é dessa maneira.

Conclusão

A interoperabilidade implementa um algoritmo sofisticado para minimizar o número de ações necessárias para atualizar a produção após a alteração do código subjacente. Chame UpdateProduction com um tempo limite seguro em cada atualização de SDS. Para cada atualização de código, você precisa decidir uma estratégia.

Minimizar a quantidade de código compilado usando git diffs ajuda no tempo de compilação, mas "atualizar" o código com ele mesmo e compilá-lo novamente ou "atualizar" as configurações com os mesmos valores não aciona ou exige uma atualização da produção.

Atualizar e compilar Regras de Negócio, Regras de Roteamento e DTLs os torna imediatamente acessíveis sem a atualização da produção.

Por fim, a atualização da produção é uma operação segura e geralmente não requer tempo de inatividade.

Links

O autor gostaria de agradecer a @James MacKeith, @Dmitry Zasypkin e @Regilo Regilio Guedes de Souza pela ajuda inestimável com este artigo.

Discussão (0)2
Entre ou crie uma conta para continuar