Skip to content

Deployment: Gerenciamento de Estado

A natureza stateless da engine Refluxo significa que ela não gerencia a persistência do estado por si só. Sua aplicação é responsável por salvar e carregar o objeto Snapshot. Essa escolha de design lhe dá total liberdade para escolher a estratégia de persistência que melhor se adapta à sua infraestrutura.

Este guia aborda as melhores práticas para gerenciar o estado de workflows em um ambiente de produção.

Onde Armazenar os Snapshots?

Você pode armazenar snapshots em qualquer banco de dados ou sistema de armazenamento que possa lidar com objetos JSON. As escolhas comuns incluem:

  • Bancos de Dados Relacionais (ex: PostgreSQL, MySQL): Uma boa escolha para muitas aplicações. Você pode armazenar o snapshot em uma coluna JSONB ou JSON. Isso permite que você consulte metadados ou propriedades do contexto, se necessário.
  • Bancos de Dados NoSQL (ex: MongoDB, DynamoDB): Excelentes para armazenar objetos do tipo documento, como os snapshots. Eles geralmente oferecem alto desempenho para leituras e escritas.
  • Caches em Memória (ex: Redis): Adequado para workflows que são críticos em termos de desempenho, mas onde a persistência a longo prazo é uma preocupação menor. Você pode combinar o Redis para workflows ativos com um banco de dados persistente para os já concluídos ou em pausa longa.

Exemplo de Schema (PostgreSQL)

Uma tabela simples para armazenar as execuções de workflow pode se parecer com isto:

sql
CREATE TABLE workflow_executions (
    id VARCHAR(255) PRIMARY KEY, -- Corresponde ao workflowId
    snapshot JSONB NOT NULL,
    status VARCHAR(50) NOT NULL,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Índice para busca eficiente de workflows ativos
CREATE INDEX idx_active_workflows ON workflow_executions (status);

Aqui, id seria seu workflowId único, e o objeto Snapshot inteiro é armazenado na coluna snapshot. A coluna status é duplicada para facilitar as consultas.

Lidando com Concorrência: Locking Otimista

Em um sistema distribuído, é possível que dois workers separados (ex: duas instâncias de uma função serverless) tentem processar o mesmo snapshot ao mesmo tempo. Isso pode levar a condições de corrida (race conditions) e a um estado corrompido.

O objeto Snapshot inclui um número de version especificamente para prevenir isso. Você pode usar isso para locking otimista (optimistic locking).

O fluxo é o seguinte:

  1. Ler e Bloquear (Lock): Quando um worker busca um snapshot do banco de dados, ele lê tanto os dados do snapshot quanto seu número de version.
  2. Executar Passo: O worker executa o próximo passo do workflow. A engine Refluxo produz um novo snapshot com um número de version incrementado.
  3. Escrita Condicional: O worker tenta salvar o novo snapshot de volta no banco de dados com uma instrução UPDATE condicional. A atualização só é bem-sucedida se o número de version no banco de dados for o mesmo de quando o worker o leu pela primeira vez.

Exemplo (pseudocódigo tipo SQL)

sql
-- `readVersion` é o número da versão que o worker leu inicialmente.
-- `newSnapshot` é o objeto snapshot com a versão incrementada.
-- `workflowId` é o ID da execução.

UPDATE workflow_executions
SET 
  snapshot = :newSnapshot, 
  status = :newSnapshotStatus,
  version = :newSnapshot.version, -- Esta é a versão incrementada
  updated_at = NOW()
WHERE
  id = :workflowId AND version = :readVersion;

Se esta instrução UPDATE afetar 0 linhas, significa que outro worker já processou este passo e atualizou o registro. O worker atual deve então descartar seu resultado e terminar graciosamente, prevenindo uma execução dupla. Este mecanismo é crucial para construir sistemas distribuídos confiáveis.