Ir para o conteúdo

Blogue ·

O filho acorda o pai

Um fluxo que chama outro fluxo pode sondar ou ser avisado. Construímos ambos, e o relógio de recurso é de um dia e não de cinco minutos por uma razão medida.

Por Provibr

Um fluxo pode agora chamar outro fluxo. A execução que chama para, a execução chamada arranca, e quando a execução chamada termina a execução que chama continua pelo fio ok ou pelo fio error.

A questão de desenho inteira nessa frase é a palavra quando. Alguma coisa tem de reparar que o filho acabou. Há duas maneiras de o arranjar e acabámos com as duas, numa ordem determinada, e a segunda tem lá dentro um número que deu que discutir.

O pai não espera, é avisado

A maneira natural de escrever isto é um pai que espera. O pai sabe por que execução está à espera, portanto pode perguntar. Sondar a cada dez segundos, ver se o filho terminou, continuar quando tiver terminado.

Está ao contrário, e a razão é que o filho já sabe. É ele que transita para terminado. Fazer o pai perguntar significa que a informação viaja de quem a tem para quem dela precisa através de uma pergunta repetida, e a frequência dessa pergunta é a latência da funcionalidade inteira.

Por isso o filho anuncia. Quando uma execução filha chega a um estado terminal, define para agora o momento de despertar da linha de espera que aponta para ela, e o trabalhador de fila vulgar apanha-a no seu ciclo seguinte. É exatamente o mesmo mecanismo que uma aprovação humana usa: decidir define esse momento para agora. Uma coluna comanda a fila, e não existe deliberadamente uma segunda via para o executor.

Esse anúncio é uma só instrução: atualizar a linha de espera em que o identificador da execução filha corresponde e o estado ainda é o de espera.

Porque é que esse identificador é uma coluna e não faz parte do bloco de estado

A continuação de uma travessia em pausa é guardada em JSON, e contém tudo aquilo de que a travessia precisa para retomar: a pilha, os nós visitados, as variáveis, os contadores. Teria sido coerente pôr lá dentro também o identificador do filho.

Em vez disso é uma coluna, e a razão é a direção em que é lido. Tudo o resto nesse bloco é lido pela travessia, de dentro. Este valor é lido de fora, por uma execução filha que quer encontrar a linha que aponta para ela. Dentro do bloco isso é uma varredura sobre todas as esperas abertas do sistema, e o índice de que precisaria para a tornar barata é esta coluna de qualquer maneira.

A chave estrangeira está em SET NULL em vez de CASCADE. Se a execução filha for limpa, a espera do pai não pode desaparecer com ela, porque nesse caso fica um pai suspenso sem nada que alguma vez o acorde. Perder a referência é sobrevivível; perder a linha não é.

O relógio de recurso é de um dia, e o número é o argumento

O anúncio é o mecanismo. O relógio é a rede de segurança para o caso em que o anúncio nunca chega: um contentor que caiu a meio de terminar o filho, uma linha tocada à mão.

O valor óbvio para uma rede de segurança é uma coisa pequena. Cinco minutos parece responsável.

Está errado, e a razão é aquilo que um filho pode conter. Uma execução filha pode conter uma aprovação humana, e uma aprovação pode ter um prazo a trinta dias. Com um relógio de cinco minutos, o pai desse filho acorda milhares de vezes ao longo desses trinta dias para descobrir que nada mudou, e cada um desses despertares é um pedido HTTP do gateway para o contentor da web.

Vinte e quatro horas custam no máximo trinta ciclos inúteis ao longo da espera mais comprida que o produto permite, e limitam a um dia o estrago de um anúncio genuinamente perdido. É essa a troca, enunciada nas unidades que interessam: quantos pedidos custa a rede de segurança quando não há nada de errado, contra quanto tempo uma falha a sério fica invisível.

A forma geral: um intervalo de repetição não é «o mais curto que conseguirmos pagar». É uma função da espera legítima mais comprida, e se não perguntou qual é essa, o intervalo é um palpite.

Um relógio que não se consegue encurtar é um relógio que não se consegue provar

Uma rede de segurança só dispara quando o mecanismo por baixo dela falhou. Com o intervalo fixado num dia, demonstrar que funciona leva um dia, portanto a ronda que a construiu entregou esse ramo como por provar, rotulado com honestidade.

A tentação é prová-lo à mão: entrar na base de dados, mover o momento de despertar para o passado, ver a execução retomar. Isso prova o retomar. Não prova o relógio, porque o relógio é precisamente aquilo que se substituiu.

Por isso o intervalo lê uma variável de ambiente, e o gancho vive no código-fonte ao lado da constante e não dentro de um ficheiro de teste. É usado por um script de ponta a ponta que o põe em poucos segundos, deixa a rede de segurança disparar de facto, e observa um pai cujo filho nunca anunciou nada a recuperar sozinho.

Duas propriedades tornam esse gancho seguro para entregar. Só consegue tornar o intervalo mais curto: o valor é limitado pela constante de produção, portanto um ambiente mal configurado nunca consegue fazer um pai esperar mais do que um dia. E tudo o que não seja um número positivo recai no valor de produção.

Essa segunda não é programação defensiva por gosto. Copiar o nosso ficheiro de ambiente de exemplo dá a variável presente e vazia, e uma cadeia de texto vazia não é indefinido. Convertê-la para número dá zero. Sem o crivo, um ficheiro de configuração copiado poria o intervalo a zero e meteria todos os pais com um filho por terminar num ciclo de despertares contra o contentor da web. Já fomos mordidos antes pela distinção entre cadeia vazia e indefinido, num sítio em que custou um 404 a uma rota de descarga.

Dois limites, cada um imposto duas vezes

Um fluxo a chamar um fluxo levanta a questão de um fluxo a chamar-se a si próprio. Há dois limites, a recursão e a profundidade, e cada um é imposto em dois sítios.

Estaticamente, quando um fluxo é guardado: percorre-se o grafo, resolvem-se os fluxos que ele chama, e um ciclo ou uma cadeia demasiado profunda é recusada com a cadeia nomeada no erro. Dinamicamente, durante uma execução: os mesmos dois limites outra vez, com os seus próprios códigos de recusa.

Ambos são necessários porque os fluxos são editados de forma independente. Dois fluxos que estão bem individualmente podem tornar-se um ciclo no momento em que alguém acrescenta uma chamada ao segundo, e nada revalida o primeiro. A verificação estática é o que dá uma mensagem de erro útil no momento em que alguém ainda o consegue corrigir; a verificação dinâmica é o que aguenta de facto.

A profundidade é uma coluna na execução e não uma coisa calculada percorrendo os pais. Isso vai contra a linha que normalmente seguimos, que é a de que tudo o que se pode derivar deve ser derivado. Aqui não se aguenta, porque a referência ao pai está em SET NULL: uma vez limpa uma execução pai, a cadeia não pode ser percorrida para trás e a profundidade de um filho em execução tornar-se-ia incognoscível exatamente no momento em que importa.

O que a ronda seguinte mediu

Os ramos que este desenho deixou em aberto foram percorridos numa ronda posterior, e dois deles são os interessantes.

Uma execução filha que desaparece por completo: a espera mantém a sua linha e perde a sua referência, o relógio de recurso acorda o pai, e o retomar não encontra nenhum filho e faz falhar esse nó com uma razão específica em vez de ficar preso. Um grafo que não se consegue ler de todo produz uma razão diferente, portanto as duas situações são distinguíveis no registo da execução.

Um subfluxo dentro de um ciclo, nas duas formas que se comportam de maneira diferente: um filho que termina dentro do pedido que o originou, e um filho que se suspende a si próprio. O primeiro nunca chega a tocar na fila. O segundo é a funcionalidade inteira.

O que registaríamos

  1. Quem sabe deve avisar e não esperar que lhe perguntem. A sondagem transforma a sua latência num valor de configuração.
  2. Reutilize o caminho de despertar que já tem. Uma decisão e um filho terminado são o mesmo acontecimento para a fila.
  3. Um valor lido de fora do bloco de estado pertence a uma coluna. É a direção da leitura que decide isto, não a coerência.
  4. SET NULL em vez de CASCADE, quando a linha que seria eliminada é a única maneira de alguém ser acordado.
  5. O intervalo de uma rede de segurança é uma função da espera legítima mais comprida, e não de quão atento gostaria de parecer.
  6. Enuncie a troca em pedidos e em horas. Trinta ciclos desperdiçados contra um dia de invisibilidade é uma decisão; «cinco minutos» é um reflexo.
  7. Uma constante que não se consegue variar é um ramo que não se consegue provar. O gancho pertence ao lado da constante.
  8. Deixe o gancho tornar as coisas apenas mais seguras, e limite-o pelo valor de produção.
  9. Uma variável de ambiente vazia não é indefinida, e convertê-la para número dá zero.
  10. Verifique um limite onde ele pode ser corrigido e onde tem de aguentar. Grafos editados de forma independente precisam dos dois.

Para que fique claro o que isto é: a verificação da fusão correu 16 de 16 passos sem uma linha de falha, a bateria de testes da web deu 4583 verdes, os pacotes, o gateway e as ferramentas em conjunto 7286 verdes, a travessia 75 verdes, a verificação estática de subfluxos 13 verdes, a execução de ponta a ponta contra a base de dados de desenvolvimento 58 verdes, a medição de destinatários 4 verdes, um teste de navegador com um trabalhador de gateway a sério 31 verdes, no qual uma pausa de noventa segundos retomou ao fim de noventa e cinco segundos, o teste do editor 9 verdes e a passagem de acessibilidade não encontrou nada em seis páginas. Por provar na altura: o relógio de recurso, um subfluxo dentro de um ciclo, uma execução filha desaparecida, e o ramo de esgotamento de repetições. Esses quatro foram percorridos na ronda seguinte.

Do trabalho de plataforma na Provibr. Como a travessia passou a ser uma coisa que se pode escrever numa linha está em cada chamada recursiva estava em posição de cauda, e a ronda que finalmente alcançou os ramos que esta deixou em aberto está em verde porque não conseguia lá chegar.

Comece com um host e um agente

Crie uma conta, instale o agente com um único comando e ligue o seu primeiro host Proxmox. O período experimental dura 14 dias e não pede quaisquer dados de pagamento.