Skip to content

Latest commit

 

History

History
521 lines (397 loc) · 17.5 KB

File metadata and controls

521 lines (397 loc) · 17.5 KB

🚀 API de Processamento Assíncrono com BullMQ

API REST construída com Node.js + TypeScript + Express que demonstra autenticação JWT, processamento assíncrono de tarefas com BullMQ (Redis) e integração mockada com serviço de IA.

📋 Índice


🧠 Visão Geral

O projeto simula um cenário real de backend onde:

  1. Um usuário faz login e recebe um token JWT.
  2. Com o token, ele cria uma tarefa (ex: "analise este texto").
  3. A tarefa é salva no Redis e enviada para uma fila BullMQ.
  4. Um Worker em processo separado consome a fila, processa a tarefa (chamando um serviço de IA mockado) e atualiza seu status.
  5. O usuário pode consultar o status da tarefa a qualquer momento.

Contexto

Este projeto foi criado como exercício prático para cobrir os requisitos de uma vaga de desenvolvedor backend Node.js, incluindo: APIs REST, filas e mensageria (BullMQ), autenticação JWT, integração com serviços de IA e processamento assíncrono com workers.


🏗 Arquitetura

┌──────────────────────────────────────────────────────────────┐
│                         CLIENTE                              │
│                  (Postman / Frontend)                        │
└────────────┬───────────────────────────────┬─────────────────┘
             │ POST /auth/login              │ POST /tasks
             │                               │ GET /tasks/:id
             ▼                               ▼
┌──────────────────────────────────────────────────────────────┐
│                    EXPRESS SERVER (porta 3000)               │
│                                                              │
│  ┌─────────────┐    ┌──────────────────┐                     │
│  │ Auth Routes │    │  Task Routes     │                     │
│  │ POST /login │    │  POST /  (auth)  │                     │
│  └──────┬──────┘    │  GET /:id (auth) │                     │
│         │           └────────┬─────────┘                     │
│         ▼                    ▼                               │
│  ┌─────────────┐    ┌──────────────────┐                     │
│  │ Auth Ctrl   │    │  Task Ctrl       │                     │
│  └──────┬──────┘    └────────┬─────────┘                     │
│         │                    │                               │
│         ▼                    ▼                               │
│  ┌─────────────┐    ┌──────────────────┐                     │
│  │ Auth Service│    │  Task Service    │──────┐              │
│  │ (JWT)       │    │  (UUID + Queue)  │      │              │
│  └─────────────┘    └──────────────────┘      │              │
└───────────────────────────────────────────────┼──────────────┘
                                                │
                                                ▼
                               ┌────────────────────────┐
                               │     REDIS (porta 6379) │
                               │  ┌──────────────────┐  │
                               │  │ BullMQ Queue     │  │
                               │  │ "task-processing"│  │
                               │  └──────────────────┘  │
                               │  ┌──────────────────┐  │
                               │  │ Task Store       │  │
                               │  │ (Hash: task:*)   │  │
                               │  └──────────────────┘  │
                               └────────────┬───────────┘
                                            │
                                            ▼
                               ┌────────────────────────┐
                               │  WORKER (processo sep.)│
                               │                        │
                               │  1. Consome job        │
                               │  2. Status → processing│
                               │  3. Chama AI Service   │
                               │  4. Status → completed │
                               └────────────────────────┘

🛠 Tecnologias

Tecnologia Versão Função
Node.js 22+ Runtime JavaScript
TypeScript 5.9 Tipagem estática
Express 5.x Framework HTTP
BullMQ 5.x Gerenciamento de filas
ioredis 5.x Cliente Redis
jsonwebtoken 9.x Autenticação JWT
uuid 13.x Geração de IDs únicos
ts-node-dev 2.x Hot-reload em dev

📁 Estrutura de Pastas

src/
├── app.ts                       # Configuração do Express (cors, json, rotas)
├── server.ts                    # Ponto de entrada — inicia o servidor na porta 3000
│
├── routes/
│   ├── auth.routes.ts           # Rota POST /auth/login
│   └── task.routes.ts           # Rotas POST /tasks e GET /tasks/:id (protegidas)
│
├── controllers/
│   ├── auth.controller.ts       # Lógica de login (recebe email/senha, retorna JWT)
│   └── task.controller.ts       # Lógica de criar e consultar tarefas
│
├── services/
│   ├── auth.service.ts          # Geração e verificação de tokens JWT
│   ├── task.service.ts          # Lógica de negócio: cria tarefa e enfileira no BullMQ
│   └── ai.service.ts            # Serviço de IA mockado (simula processamento)
│
├── middlewares/
│   └── auth.middleware.ts       # Middleware que valida o JWT e injeta req.user
│
├── queue/
│   ├── redis.ts                 # Conexão com Redis (localhost:6379)
│   ├── task.queue.ts            # Instância da fila BullMQ "task-processing"
│   └── worker.ts                # Worker que consome a fila e processa tarefas
│
├── stores/
│   └── task.store.ts            # CRUD de tarefas no Redis (usando Hash)
│
├── repositories/
│   └── task.repository.ts       # Repository in-memory (Map) — alternativo
│
└── types/
    ├── tasks.ts                 # Tipos: Task, TaskStatus
    └── express.d.ts             # Extensão de tipagem do Express (req.user)

✅ Pré-requisitos

Antes de rodar o projeto, você precisa ter instalado:

  • Node.js v18+ (download)
  • Redis rodando em localhost:6379
    • Via Docker: docker run -d --name redis -p 6379:6379 redis
    • Via instalação nativa: docs Redis

⚠️ O Redis é obrigatório. O BullMQ e o armazenamento de tarefas dependem dele.


📦 Instalação

# Clone o repositório
git clone <url-do-repositorio>
cd api-auth-bullmq

# Instale as dependências
npm install

▶️ Como Executar

O projeto precisa de dois processos rodando simultaneamente: o servidor da API e o worker da fila.

1. Suba o Redis

# Se estiver usando Docker:
docker run -d --name redis -p 6379:6379 redis

2. Inicie o Servidor (Terminal 1)

npm run dev

Saída esperada:

🚀 Server running on http://localhost:3000

3. Inicie o Worker (Terminal 2)

npm run worker

O worker ficará ouvindo a fila task-processing e processando tarefas em background.

Scripts disponíveis

Comando Descrição
npm run dev Inicia o servidor em modo desenvolvimento (hot-reload)
npm run worker Inicia o worker BullMQ para processar tarefas
npm run build Compila TypeScript para JavaScript (dist/)
npm start Roda a versão compilada do servidor

📡 Endpoints da API

Saúde / Health Check

GET /ping

Resposta:

{ "message": "Pong!" }

⚡ Autenticação

POST /auth/login

Realiza login e retorna um token JWT.

Request Body:

{
  "email": "usuario@email.com",
  "password": "qualquer-senha"
}

ℹ️ O login é mockado — aceita qualquer email/senha, desde que ambos sejam informados.

Resposta (200):

{
  "user": {
    "id": "user-123",
    "email": "usuario@email.com"
  },
  "token": "eyJhbGciOiJIUzI1NiIs..."
}

Erro (400):

{ "message": "Email e senha são obrigatórios" }

📝 Tarefas

🔒 Todas as rotas de tarefas exigem autenticação via header Authorization: Bearer <token>.

POST /tasks

Cria uma nova tarefa e a envia para a fila de processamento.

Headers:

Authorization: Bearer <token-jwt>

Request Body:

{
  "text": "Texto para ser analisado pela IA"
}

Resposta (201):

{
  "task": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "status": "queued"
  }
}

GET /tasks/:id

Consulta o status e resultado de uma tarefa.

Headers:

Authorization: Bearer <token-jwt>

Resposta (200) — Tarefa em processamento:

{
  "id": "a1b2c3d4-...",
  "userId": "user-123",
  "status": "processing",
  "result": "",
  "createdAt": "2025-01-01T12:00:00.000Z",
  "updatedAt": "2025-01-01T12:00:01.000Z"
}

Resposta (200) — Tarefa concluída:

{
  "id": "a1b2c3d4-...",
  "userId": "user-123",
  "status": "completed",
  "result": "Resumo gerado pela IA: Texto para ser analisado pela I...",
  "createdAt": "2025-01-01T12:00:00.000Z",
  "updatedAt": "2025-01-01T12:00:03.000Z"
}

Erro (404):

{ "message": "Task not found" }

Erro (401) — Sem token ou token inválido:

{ "message": "Token não informado" }
// ou
{ "message": "Token inválido" }

Status possíveis de uma tarefa

Status Descrição
queued Tarefa criada e aguardando na fila
processing Worker pegou a tarefa e está processando
completed Processamento concluído com sucesso
failed Ocorreu um erro durante o processamento

🔄 Fluxo Completo

1. Cliente faz POST /auth/login
   └─► Recebe token JWT

2. Cliente faz POST /tasks com token
   └─► API cria tarefa no Redis (status: queued)
   └─► API enfileira job no BullMQ (fila: task-processing)
   └─► Retorna { id, status: "queued" }

3. Worker consome o job da fila
   └─► Atualiza status para "processing"
   └─► Chama ai.service.ts (mock: aguarda 2s e retorna resumo)
   └─► Atualiza status para "completed" + resultado

4. Cliente faz GET /tasks/:id
   └─► Recebe status atual + resultado (se concluído)

📦 Detalhamento dos Módulos

🔐 Módulo de Autenticação (auth)

Arquivos: routes/auth.routes.tscontrollers/auth.controller.tsservices/auth.service.ts

  • Gera um token JWT com jsonwebtoken usando a chave secreta "super-secret-key".
  • O token expira em 1 hora.
  • O payload do token contém { id, email }.
  • O login é simplificado (mock): aceita qualquer email/senha.
  • Em produção, seria necessário validar credenciais contra um banco de dados e hash de senha (ex: bcrypt).

Middleware: middlewares/auth.middleware.ts

  • Extrai o token do header Authorization: Bearer <token>.
  • Decodifica e valida o token.
  • Injeta req.user = { id } para uso nos controllers.
  • Retorna 401 se o token estiver ausente ou inválido.

📋 Módulo de Tarefas (tasks)

Arquivos: routes/task.routes.tscontrollers/task.controller.tsservices/task.service.ts

  • Criar tarefa: gera UUID, salva no Redis via task.store.ts, e enfileira no BullMQ.
  • Consultar tarefa: busca os dados diretamente do Redis (HGETALL task:<id>).
  • Todas as rotas passam pelo authMiddleware (autenticação obrigatória).

⚙️ Módulo de Filas (queue)

Arquivos: queue/redis.ts, queue/task.queue.ts, queue/worker.ts

Conexão Redis (redis.ts)

  • Usa ioredis para conectar em localhost:6379.
  • maxRetriesPerRequest: null — necessário para BullMQ funcionar corretamente.

Fila (task.queue.ts)

  • Cria uma fila BullMQ chamada "task-processing" conectada ao Redis.
  • Jobs são adicionados com taskQueue.add("process-task", { taskId, text, userId }).

Worker (worker.ts)

  • Escuta a fila "task-processing".
  • Para cada job:
    1. Atualiza status da tarefa para "processing".
    2. Chama o ai.service.ts com o texto da tarefa.
    3. Atualiza status para "completed" e salva o resultado.
  • Se o job falhar, atualiza status para "failed".
  • Roda como processo separado via npm run worker.

🤖 Serviço de IA (ai.service.ts)

  • Simula uma chamada a um serviço de IA (ex: OpenAI).
  • Aguarda 2 segundos (simulando latência) e retorna um resumo do texto.
  • Retorno: "Resumo gerado pela IA: <primeiros 50 caracteres>...".
  • Em produção, este mock seria substituído por uma chamada real à API da OpenAI ou Azure AI.

💾 Armazenamento (stores/task.store.ts)

  • Usa Redis Hashes para armazenar dados das tarefas.
  • Padrão de chave: task:<uuid>.
  • Cada tarefa expira automaticamente em 1 hora (EXPIRE).
  • Campos armazenados: id, userId, status, result, createdAt, updatedAt.

ℹ️ O projeto também contém um repositories/task.repository.ts com armazenamento em memória (Map), mas o fluxo principal usa o task.store.ts com Redis.


🏷 Tipos TypeScript (types/)

  • tasks.ts: Define TaskStatus ("queued" | "processing" | "completed" | "failed") e a interface Task.
  • express.d.ts: Estende o tipo Request do Express para incluir req.user com { id: string }.

🧪 Testando com Postman

Passo 1 — Login

POST http://localhost:3000/auth/login
Content-Type: application/json

{
  "email": "eduardo@email.com",
  "password": "123456"
}

✅ Copie o token da resposta.

Passo 2 — Criar Tarefa

POST http://localhost:3000/tasks
Content-Type: application/json
Authorization: Bearer <cole-o-token-aqui>

{
  "text": "Quero que a IA analise este texto sobre inteligência artificial"
}

✅ Copie o id da tarefa na resposta.

Passo 3 — Consultar Tarefa

GET http://localhost:3000/tasks/<cole-o-id-aqui>
Authorization: Bearer <cole-o-token-aqui>

⏳ Se consultar imediatamente, o status pode ser "queued" ou "processing". Aguarde ~2 segundos e consulte novamente para ver "completed" com o resultado.

Passo 4 — Testar Health Check

GET http://localhost:3000/ping

🚧 Possíveis Melhorias

Este projeto é um MVP para demonstração. Algumas melhorias para produção seriam:

  • Banco de dados real (PostgreSQL com Drizzle) para persistência de tarefas e usuários
  • Hash de senha (bcrypt) para autenticação real
  • Variáveis de ambiente (.env) para segredos e configurações
  • Validação de dados (Zod ou Joi) nos inputs
  • Integração real com OpenAI substituindo o mock do ai.service.ts
  • Docker + docker-compose para subir API + Redis + DB com um comando
  • Testes automatizados com Jest (unitários e de integração)
  • CI/CD com GitHub Actions para rodar testes e deploy
  • Rate limiting e proteção contra abusos
  • Webhook notificando quando uma tarefa for concluída
  • Logs estruturados (Winston ou Pino) para observabilidade
  • Scheduler (cron com BullMQ) para limpar tarefas antigas automaticamente