Documentação / Arquitetura Desacoplada: Frontend, Backend e Worker Isolados

Arquitetura Desacoplada: Frontend, Backend e Worker Isolados

Entrar

Arquitetura Desacoplada: Frontend, Backend e Worker Isolados

Este documento descreve uma arquitetura de microsserviços onde cada componente principal (Frontend, Backend, Worker) opera de forma isolada, com seu próprio ciclo de vida, repositório (opcional) e orquestração via Docker Compose. A comunicação entre os serviços ocorre via HTTP (para API) e através de serviços de dados externos (Banco de Dados e Redis).

Visão Geral

Nesta arquitetura, removemos a dependência de uma rede Docker interna compartilhada. Em vez disso, tratamos cada serviço como se estivesse rodando em uma infraestrutura separada.

  • Backend (API): Expõe endpoints HTTP públicos. Conecta-se diretamente ao Banco de Dados e Redis (gerenciados externamente).
  • Worker: Processa tarefas em background. Conecta-se aos mesmos Banco de Dados e Redis externos que o Backend.
  • Frontend: Aplicação estática (SPA) servida por um servidor web. O navegador do usuário consome a API do Backend via internet pública.
  • Serviços de Dados (DB/Redis): Hospedados externamente (ex: AWS RDS, MongoDB Atlas, Redis Cloud) ou em um servidor dedicado, acessíveis via URL de conexão.

Fluxo de Comunicação

  1. Usuário -> Frontend: O navegador carrega a aplicação.
  2. Frontend (Navegador) -> Backend: O JavaScript no navegador faz requisições HTTP para a API (ex: https://api.seudominio.com).
  3. Backend -> Dados: A API lê/escreve no PostgreSQL e Redis externos.
  4. Worker -> Dados: O Worker monitora o Redis (filas) e processa dados no PostgreSQL, sem comunicação direta com a API.

Configuração dos Serviços

Cada serviço possui seu próprio docker-compose.yml e arquivo .env.

1. Backend

Responsável pela regra de negócio e API.

Arquivo: backend/docker-compose.yml

version: '3.8'

services:
  api:
    image: seu-registry/backend:latest
    container_name: backend-api
    restart: always
    ports:
      - "3000:3000" # Porta exposta para receber requisições do Frontend/Internet
    env_file: .env
    extra_hosts:
      - "host.docker.internal:host-gateway" # Para Linux, caso precise acessar algo no host

Configuração (.env):

DATABASE_URL=postgres://user:pass@db-host-externo:5432/pilot_db
REDIS_URL=redis://:pass@redis-host-externo:6379
PORT=3000

2. Worker

Processamento de tarefas assíncronas (envio de emails, relatórios, etc.).

Arquivo: worker/docker-compose.yml

version: '3.8'

services:
  worker:
    image: seu-registry/worker:latest
    container_name: worker-app
    restart: always
    # Workers geralmente não precisam de portas expostas (inbound)
    env_file: .env
    extra_hosts:
      - "host.docker.internal:host-gateway"

Configuração (.env): Deve apontar para os mesmos serviços de dados do Backend.

DATABASE_URL=postgres://user:pass@db-host-externo:5432/pilot_db
REDIS_URL=redis://:pass@redis-host-externo:6379

3. Frontend

Servidor web (Nginx/Apache) servindo os arquivos estáticos da SPA (React/Vue/Angular).

Arquivo: frontend/docker-compose.yml

version: '3.8'

services:
  web:
    image: seu-registry/frontend:latest
    container_name: frontend-web
    restart: always
    ports:
      - "80:80" # Porta HTTP padrão
    environment:
      # URL da API que será injetada no build ou runtime do frontend
      - VITE_API_URL=https://api.seudominio.com

Vantagens desta Arquitetura

1. Escalabilidade Independente (Horizontal Scaling)

Permite alocar recursos especificamente onde há gargalo.

  • Cenário: Se a API estiver lenta devido a muitos acessos, você pode subir 5 réplicas do container backend-api sem precisar duplicar o Frontend ou o Worker.
  • Cenário: Se houver muitas tarefas pesadas (ex: processamento de imagens), você pode escalar apenas os workers para processar a fila mais rápido, sem impactar a latência da API.

2. Resiliência e Isolamento de Falhas

Falhas em um componente não derrubam o sistema inteiro.

  • Se o Worker travar ou consumir 100% da CPU, a API continua respondendo normalmente aos usuários.
  • Se a API cair para manutenção, o Frontend continua sendo servido (podendo exibir uma mensagem amigável de erro/manutenção).

3. Deploy Sem Downtime (Zero Downtime)

Atualizações seguras e granulares.

  • Você pode atualizar o Frontend (ex: mudar texto ou cor) sem reiniciar o Backend.
  • Você pode corrigir um bug no Worker sem interromper a navegação dos usuários no site.

4. Bancos de Dados Gerenciados (Externalizados)

Ao tirar o estado (DB/Redis) de dentro do Docker Compose:

  • Segurança: Backups, updates e patches de segurança são gerenciados pelo provedor (AWS, Azure, etc.).
  • Persistência: Elimina o risco de perder dados se um container ou volume for deletado acidentalmente.
  • Performance: Bancos de dados dedicados geralmente têm performance de I/O muito superior a bancos rodando em containers compartilhados.

5. Flexibilidade Tecnológica

Liberdade para evoluir a stack.

  • O Frontend não precisa saber em que linguagem o Backend foi escrito, apenas consome JSON.
  • O Worker pode ser reescrito em outra linguagem (ex: Go/Rust para performance) sem afetar o Backend, desde que ambos concordem no formato das mensagens no Redis/DB.

Gerenciamento de Código Compartilhado

Como Backend e Worker frequentemente utilizam as mesmas entidades (ex: definições de Banco de Dados, Tipos, Utilitários), é necessário uma estratégia para evitar duplicação e inconsistências.

1. Pacote Interno Compartilhado (Recomendado)

A abordagem mais moderna e segura é extrair o código comum para um pacote interno (packages/core ou shared).

  • Funcionamento: Cria-se uma biblioteca interna que exporta DTOs, Schemas do Banco (Prisma/TypeORM) e Helpers.
  • Integração: Backend e Worker declaram esse pacote como dependência no package.json ("dependencies": { "@app/core": "file:../packages/core" }).
  • Build: No momento do build da imagem Docker, o gerenciador de pacotes (npm/yarn/pnpm) ou ferramentas de monorepo (Turborepo/Nx) cuidam de copiar e linkar esse código.
  • Vantagem: Fonte única de verdade (Single Source of Truth). Se uma tabela muda, você atualiza o pacote core e reconstrói os serviços.

2. Git Submodules / Subtree

Manter o código comum em um repositório Git separado e importá-lo dentro das pastas dos projetos.

  • Funcionamento: O código compartilhado é "clonado" dentro de backend/src/shared e worker/src/shared.
  • Vantagem: Desacoplamento total de gerenciadores de pacote.
  • Desvantagem: Complexidade operacional (necessidade de dar pull manual nos submodules para atualizar).

3. Duplicação de Código (Não Recomendado)

Copiar e colar arquivos entre os projetos.

  • Risco: Altíssima probabilidade de divergência (ex: Backend espera um campo userId e Worker espera user_id), causando erros difíceis de rastrear em produção.