1 pontos por GN⁺ 2023-10-27 | 1 comentários | Compartilhar no WhatsApp
  • Flawless é um motor de execução de computação durável que ajuda o código a continuar executando até o fim mesmo quando ocorrem falhas
  • Os workflows são escritos como funções Rust comuns, mas são compilados para WebAssembly em vez de código nativo e executados em um ambiente determinístico
  • Efeitos colaterais não determinísticos surgem apenas nos pontos em que há contato com o mundo externo, como requisições HTTP ou geração de números aleatórios, e o Flawless os armazena em logs
  • Se a execução for interrompida, ele usa os logs salvos para recuperar até o mesmo estado, sem repetir efeitos colaterais já executados
  • Os desenvolvedores podem representar o estado persistente com código e variáveis locais sem modelar todo o estado diretamente no banco de dados, permitindo retomar a partir do ponto de interrupção mesmo após reiniciar o servidor

Modelo de execução que representa estado persistente com código

  • O Flawless é um motor de computação durável que executa o código até sua conclusão mesmo quando ocorrem falhas de hardware ou software
  • Experiências de usuário complexas exigem UIs e estados complexos, mas modelar todo o estado diretamente dentro do banco de dados é difícil
  • Para que o usuário não perca o progresso mesmo ao recarregar a página por engano, aplicações modernas precisam de armazenamento persistente
  • O Flawless busca permitir que o estado persistente seja modelado com código e variáveis locais, facilitando a expressão de comportamentos complexos da aplicação

Execução baseada em WebAssembly e recuperação de falhas

  • Os workflows são escritos como funções Rust comuns e podem incluir lógica arbitrária
  • As funções são compiladas para WebAssembly em vez de código nativo e executadas em um ambiente totalmente determinístico
  • A não determinismo só é introduzido ao interagir com o mundo externo, como ao fazer requisições HTTP ou gerar números aleatórios
  • O Flawless armazena esses logs de efeitos colaterais não determinísticos para uso na recuperação
    • Se a execução de um workflow for interrompida, ele o executa novamente até alcançar o mesmo estado
    • Efeitos colaterais já executados não são executados novamente
    • A quantidade de dados que precisa ser armazenada é minimizada, e o restante é recalculado sob demanda quando ocorre uma falha
  • Esse modelo de execução permite observar melhor o comportamento de todo o sistema
    • É possível analisar o caminho exato de execução de workflows concluídos ou em andamento
    • Graças ao ambiente de execução determinístico, fica mais fácil lidar com bugs difíceis de reproduzir
  • Os desenvolvedores podem reduzir a carga de persistência de estado e se concentrar mais na escrita da lógica de negócio
  • Mesmo que seja necessário reiniciar o servidor para manutenção, ao reiniciar o motor Flawless o workflow continua a partir do ponto em que parou
  • Em 9 de dezembro de 2024, está disponível o Flawless Beta 3

1 comentários

 
GN⁺ 2023-10-27
Comentários no Hacker News
  • Fico curioso sobre como lidarão com versionamento de workflows. Vejo isso como o problema mais difícil em sistemas como Temporal/Cadence

    • Sou o autor. Para workflows de longa duração, ou que na prática rodam para sempre, acho que a solução mais intuitiva é permitir upgrades sem downtime
      O upgrade só tem sucesso quando o novo código consegue reproduzir exatamente o registro anterior de efeitos colaterais. Depois que o novo código faz o catch-up, ele simplesmente continua executando dali em diante
      Se o novo código divergir do histórico anterior, o upgrade falha e volta para o código antigo. Nesse caso, uma pessoa precisa intervir para verificar o que deu errado
      Existem outras abordagens, mas acho que essa é a mais simples de entender e usar na prática. Durante o desenvolvimento, também dá para usar logs existentes para testar se o código diverge
    • Fico curioso se o problema é que já existem workflows vivos e em andamento, e você quer atualizar o workflow sem quebrá-los
      Também fico curioso se a ideia é manter várias versões ao mesmo tempo ou se é preciso um jeito de migrar os que estão em andamento para a definição de workflow mais recente
    • Exato. Essa é uma área em que o Conductor lida bem por você
  • Sinto que nossa área está ficando cada vez mais próxima da arquitetura ou da medicina. Com tecnologias assim, podemos sair da fase de ficar mexendo e entrar em uma cultura de engenharia séria
    Perguntando de forma breve: como vocês impedem que o efeito de ataques DoS seja persistido nesse tipo de sistema?

    • A expressão “ficando mais próxima da arquitetura e da medicina” soa como um nonsense gerado por aprendizado de máquina
      Arquitetura tem mais a ver com lidar com opiniões subjetivas dentro de restrições regulatórias, e medicina é conhecimento empírico validado por experimentos. É difícil dizer que qualquer uma das duas se parece com engenharia
    • Nem arquitetura nem medicina são áreas de engenharia, então não entendo por que ficar mais perto delas seria um caminho para uma cultura de engenharia
      Arquitetura é mais próxima de uma forma de arte, e os cursos de arquitetura nas universidades normalmente ficam em faculdades de artes
      Medicina, assim como engenharia, é uma ciência aplicada, mas não é em si uma área de engenharia
  • Fico curioso se esse determinismo se estende a cálculos de ponto flutuante
    Em jogos multiplayer, o estado dos clientes acumulava pequenos desvios em cálculos de ponto flutuante em relação ao estado do servidor, então era preciso ressincronizar periodicamente; historicamente, isso foi um ponto bem doloroso

  • Onde o estado dos efeitos colaterais é armazenado? Por exemplo, se eu tiver uma AWS Lambda que quero tornar idempotente, a Lambda não tem armazenamento local que persista entre execuções
    A menos que se monte algo como um volume EBS, o estado não persiste; então dá para assumir que o estado pode ser armazenado em um DB?

    • Acho que essa será a parte pela qual você vai pagar quando o produto for lançado
  • Gostei da animação que mostra o princípio central e o modo de funcionamento. Ficou muito bem feita

    • Obrigado. Eu a programei diretamente só com HTML, CSS e JavaScript, e coloquei muito esforço e carinho nela
      O código não é exatamente bonito, mas a implementação é direta; se quiser conferir, está aqui: https://flawless.dev/js/how-does-it-work-animation.js
    • Como chamadas a endpoints externos quebram com muito mais frequência por causa de timeouts, eu também gostaria de ver a falha acontecendo na etapa de execução HTTP
  • Parece interessante, mas fico curioso se será fácil marcar funções como tendo efeitos colaterais sem cometer erros
    No exemplo, presumo que a geração de números aleatórios seja um efeito colateral porque vem do gerador de aleatórios fornecido pelo flawless. Seria possível com uma função Rust comum também?
    Imagino que também exista algum tipo de harness de testes para o desenvolvedor verificar o workflow

    • Sou o autor do flawless. Usando WebAssembly, dá para tornar isso bastante seguro por padrão
      O WebAssembly exige que chamadas ao host sejam declaradas explicitamente dentro do módulo. Se você tentar usar outra chamada ao host que não seja fornecida pelo flawless, o módulo não poderá ser instanciado
      No ecossistema WebAssembly, também há vários trabalhos de padronização em andamento. Por exemplo, se você usa o crate Rust rand e compila para WebAssembly, ele usa funções de host WASI para gerar números aleatórios
      Enquanto esperamos pela padronização de wasi, wasi-http etc., por enquanto estamos expondo nossas próprias interfaces
      Claro que há uma grande desvantagem: nem todo código Rust pode ser compilado para WebAssembly. Ainda assim, acho melhor a abordagem de negação por padrão, que garante que efeitos colaterais não intencionais nunca ocorram
    • Pelo fato de o gerador de números aleatórios e as requisições HTTP estarem ambos sob o namespace flawless, parece que, em vez de dar acesso a todo o ecossistema Rust, a ideia será usar algo como std::flawless
      O harness deve resolver a maioria dos problemas, mas fico curioso sobre quantas funcionalidades será possível mapear
      Até agora, parece mais um runtime de scripting que usa Rust
  • Parece uma alternativa em Rust ao Temporal que usa WASM como runtime. Gostei
    Sou fundador da windmill.dev, e nós também lidamos com um motor durável feito em Rust. Só que é bem menos elegante. Dividimos os workflows em etapas claras em Python/TypeScript/Go/Bash e, para retomar a partir de uma etapa inacabada, reiniciamos desde a última etapa e persistimos permanentemente o resultado de cada etapa em jsonb no banco Postgres
    Os casos de uso são claramente diferentes, e o flawless parece ser bem leve, como o site diz, a ponto de poder ser usado para modelar o estado de fluxos de UI e escalar para milhões deles em servidores pequenos
    Fantástico. Espero que um dia Rust mova todos os sistemas distribuídos

  • “Todo programa concorrente suficientemente complexo escrito em outra linguagem contém uma implementação ad hoc, informalmente especificada, cheia de bugs e lenta de metade do Erlang” — Primeira Lei de Programação de Virding

    • O objetivo do Flawless parece ser armazenar o estado intermediário de algum workflow e, em caso de falha, reiniciar a partir do ponto intermediário
      Isso é bem diferente de Erlang. Erlang foi criado principalmente para desenvolver software mesmo quando só havia equipamentos protótipo com muitos problemas de hardware
      Para mim, as duas abordagens parecem opostas. O Flawless pode ficar preso em um loop tentando concluir um workflow que trava no meio, enquanto Erlang pode descartar tranquilamente os 50% do tráfego que acionaram um bug de hardware
    • O primeiro post do blog menciona Erlang/OTP: https://flawless.dev/essays/when-letting-it-crash-is-not-eno...
    • Isso não parece resolver exatamente o mesmo problema que Erlang
      Erlang resolve isso praticamente eliminando estado persistente. Quase todo o estado fica em lugares como filas de mensagens ou bancos de dados externos
      O Flawless parece resolver o problema com uma técnica parecida com journaling de sistema de arquivos, mas não exatamente igual. A ideia é registrar quando efeitos colaterais são executados
      O journaling de sistema de arquivos serve para reexecutar depois de um crash, mas aqui é para tornar desnecessário reexecutar
      Não está claro em quais áreas isso se encaixa melhor, mas a sobreposição com as áreas em que Erlang se encaixa bem não parece ser total
    • https://codesync.global/media/erlangrt-a-beam-vm-reimplement...
    • Então, para que o programa cheio de bugs e informalmente especificado supere as expectativas, ele só precisa ser rápido
  • Muito legal. Em Ambient, um runtime de jogos em WASM, temos um problema parecido. Há processos concorrentes e as interações podem precisar ser repetidas, então a abordagem mostrada aqui é interessante
    Mas fico curioso sobre a relação com o Lunatic. O Lunatic ainda está em desenvolvimento, isto é um projeto paralelo, ou são coisas totalmente separadas?
    https://lunatic.solutions/

    • Boa observação. Isto foi feito por Bernard Kolobara, CEO e cofundador do Lunatic
      https://kolobara.com
  • “Imagine que você inicia um cálculo arbitrário e o sistema garante que ele será executado até a conclusão e que todas as operações serão realizadas exatamente uma vez”
    Fico curioso para saber como isso é garantido. Em sistemas distribuídos, a entrega exatamente uma vez não é impossível?

    • Em cima de um sistema de entrega pelo menos uma vez, é possível ter processamento exatamente uma vez usando chaves de idempotência
    • Se você está falando do teorema CAP, é preciso um pouco mais de explicação: https://www.infoq.com/articles/cap-twelve-years-later-how-th...
    • Não é impossível. No teorema CAP, basta escolher CP. Ou seja, abrir mão da disponibilidade
      Se o sistema puder avançar, a mensagem será entregue exatamente uma vez
      Se for preciso uma prova de existência, o NFSv3 já fez isso funcionar nos anos 1980. Não sei se foi o primeiro
    • O texto diz “imagine”. Não sei onde está a frase citada e também não consegui encontrá-la no original