Deployment: Padrões Serverless
O modelo de execução "passo a passo" e stateless da engine Refluxo é uma combinação perfeita para ambientes serverless como AWS Lambda, Google Cloud Functions ou Cloudflare Workers. Essas plataformas são projetadas para computações de curta duração e orientadas a eventos, que é exatamente como a engine opera.
Este guia descreve um padrão comum e eficaz para implantar uma aplicação baseada em Refluxo em uma arquitetura serverless.
O Padrão Central: A Função "Dispatcher"
Em vez de ter um processo de longa duração, você tem uma única função serverless stateless (vamos chamá-la de "Dispatcher") que é responsável por executar um passo de um workflow.
A arquitetura depende de um banco de dados persistente (para o estado) e de uma fila de mensagens (para o agendamento).
O fluxo é o seguinte:
- Trigger (Acionador): Um evento inicial (ex: uma requisição HTTP a um API Gateway, um novo arquivo em um bucket S3) invoca a função Dispatcher com um payload inicial.
- Criar ou Carregar Estado: O Dispatcher cria um novo
Snapshotou carrega um existente do banco de dados (ex: DynamoDB). - Executar Um Passo: Ele chama
engine.executeStep()com o snapshot. Esta é uma diferença crucial em relação aoengine.execute(), pois queremos processar apenas um único nó para manter o tempo de execução da função curto. - Processar o Resultado: O Dispatcher inspeciona o novo snapshot retornado pelo
executeStep(). - Salvar Estado: Ele salva o novo snapshot no banco de dados.
- Agendar Próximo Passo:
- Se o status do novo snapshot for
active, o Dispatcher envia uma mensagem para si mesmo através de uma fila de mensagens (ex: SQS) para acionar o próximo passo imediatamente. O payload da mensagem é simplesmente oworkflowId. - Se o status for
error(aguardando uma retentativa), ele envia uma mensagem para si mesmo com um atraso (delay), calculado a partir do timestampretryState.nextRetryAt. - Se o status for
paused,completedoufailed, ele não faz nada. A execução do workflow para até que outro evento externo (como um webhook) a acione novamente.
- Se o status do novo snapshot for
Representação Visual
Exemplo: AWS Lambda + SQS + DynamoDB
Aqui está um exemplo simplificado de como uma função Dispatcher poderia se parecer na AWS.
import { SQSClient, SendMessageCommand } from "@aws-sdk/client-sqs";
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
// Suponha que você tenha arquivos de serviço para interagir com o DynamoDB
import { getSnapshot, saveSnapshot } from "./database";
import { engine } from "./engine"; // Sua instância da engine configurada
const sqsClient = new SQSClient({});
const queueUrl = process.env.QUEUE_URL;
export async function handler(event) {
// O evento pode vir de um API Gateway, SQS, etc.
const { workflowId, externalPayload, isNew } = parseEvent(event);
let snapshot;
if (isNew) {
snapshot = engine.createInitialSnapshot(workflowId, "start-node");
} else {
snapshot = await getSnapshot(workflowId);
// Se o workflow já terminou, não faz nada.
if (["completed", "failed"].includes(snapshot.status)) return;
}
// Define o status como ativo se estava pausado ou em retentativa
if (["paused", "error"].includes(snapshot.status)) {
snapshot.status = "active";
}
// Executa apenas um passo
const newSnapshot = await engine.executeStep(snapshot, externalPayload);
// Salva o novo estado
await saveSnapshot(newSnapshot);
// Agenda a próxima ação
if (newSnapshot.status === "active") {
// Aciona o próximo passo imediatamente
await sqsClient.send(new SendMessageCommand({
QueueUrl: queueUrl,
MessageBody: JSON.stringify({ workflowId: newSnapshot.workflowId })
}));
} else if (newSnapshot.status === "error" && newSnapshot.retryState) {
// Aciona o próximo passo com um atraso para a retentativa
const delaySeconds = Math.ceil(
(newSnapshot.retryState.nextRetryAt - Date.now()) / 1000
);
await sqsClient.send(new SendMessageCommand({
QueueUrl: queueUrl,
MessageBody: JSON.stringify({ workflowId: newSnapshot.workflowId }),
DelaySeconds: Math.max(0, Math.min(delaySeconds, 900)), // Atraso máx. do SQS é de 15 min
}));
}
// Se estiver pausado, concluído ou falho, o processo para aqui.
}Este padrão é altamente escalável, resiliente e econômico, pois você paga apenas pelos breves momentos em que seu workflow está processando ativamente um passo.