🚂 Deploy no Railway - Guia Completo
O Cidadão.AI utiliza Railway como plataforma de produção desde outubro de 2024, alcançando 99.9% de uptime com arquitetura multi-serviço (Web + Worker + Beat).
🔗 Produção: https://cidadao-api-production.up.railway.app
🎯 Por Que Railway?
Vantagens para o Cidadão.AI
| Característica | Railway | Alternativas |
|---|---|---|
| Multi-Serviço | ✅ Procfile nativo | Limitado |
| Celery + Beat | ✅ Suporte completo | Difícil |
| Auto-Deploy | ✅ Push to deploy | Manual |
| Managed Redis | ✅ 1-click | Separado |
| Zero Config | ✅ Auto-detect | Configuração complexa |
| Custo | $30/mês produção | $50-100/mês |
| Uptime SLA | 99.9% | Variável |
Arquitetura Final no Railway
📋 Pré-requisitos
Conta Railway
# 1. Criar conta gratuita
https://railway.app/
# 2. Conectar GitHub
Settings → Conectar GitHub → Autorizar
# 3. Instalar Railway CLI (opcional)
npm install -g @railway/cli
# 4. Login via CLI
railway login
Repositório Git
# Estrutura necessária do repositório
cidadao.ai-backend/
├── Procfile # ✅ OBRIGATÓRIO - Define os 3 serviços
├── requirements.txt # ✅ OBRIGATÓRIO - Dependências Python
├── runtime.txt # ✅ OBRIGATÓRIO - python-3.10.12
├── src/
│ └── api/
│ └── app.py # ✅ FastAPI app
└── .gitignore # ❌ Não incluir .env, secrets
REMOVA estes arquivos se existirem - causam conflitos com Procfile:
- ❌
railway.toml - ❌
railway.json - ❌
nixpacks.toml
Railway usa esta ordem de prioridade:
- Procfile ← Usamos este ✅
- railway.toml / railway.json
- nixpacks.toml
- Dockerfile
🚀 Setup Inicial - Passo a Passo
1. Criar Projeto no Railway
Via Dashboard (Recomendado)
Passos detalhados:
- Dashboard → New Project
- "Deploy from GitHub repo"
- Selecionar
anderson-ufrj/cidadao.ai-backend - Railway detecta automaticamente:
- Python 3.10
- requirements.txt
- Procfile
- Primeiro deploy cria apenas o serviço web
- Aguardar build (3-5 minutos)
- Obter URL gerado:
https://cidadao-api-production.up.railway.app
Via Railway CLI
# 1. Link ao repositório
cd cidadao.ai-backend
railway link
# 2. Criar projeto
railway init
# 3. Deploy
git push origin main
# Railway detecta push e faz deploy automático
2. Configurar Variáveis de Ambiente
NUNCA commite secrets no Git. Configure via Railway Dashboard ou CLI.
Via Dashboard
Settings → Variables → Add Variable
Obrigatórias
# Database (Supabase)
SUPABASE_URL=https://xyzabc.supabase.co
SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
# Security Keys (gerar com: python3 -c "import secrets; print(secrets.token_urlsafe(64))")
JWT_SECRET_KEY=ZreYJKfHts0RU3EUmG7YQKxvPq-n8wLzX9BcDfGhIjKlMnOpQr...
SECRET_KEY=gm_vrQ054CziyUEWbVXYz123456789abcdefghijklmnopqrstuvw...
# Environment
ENVIRONMENT=production
APP_ENV=production
Opcionais
# APIs Externas
TRANSPARENCY_API_KEY=e24f842355f72fb8c4d1a2b3c4d5e6f7
DADOS_GOV_API_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
GROQ_API_KEY=gsk_abc123xyz789...
# Redis (auto-provisionado se adicionar Redis service)
REDIS_URL=redis://default:password@redis.railway.internal:6379
Auto-Provisionadas (Railway injeta automaticamente)
PORT=8000 # Porta dinâmica (Railway gerencia)
RAILWAY_ENVIRONMENT=production
RAILWAY_PROJECT_ID=abc-123
RAILWAY_SERVICE_ID=def-456
Via Railway CLI
# Adicionar variáveis via CLI
railway variables set SUPABASE_URL="https://xyzabc.supabase.co"
railway variables set JWT_SECRET_KEY="$(python3 -c 'import secrets; print(secrets.token_urlsafe(64))')"
# Listar variáveis
railway variables list
# Remover variável
railway variables unset DEBUG
3. Adicionar PostgreSQL (Supabase)
Railway não oferece PostgreSQL managed próprio em preço competitivo. Use Supabase (gratuito até 500MB):
# 1. Criar projeto no Supabase
https://app.supabase.com/
# 2. Obter credenciais
Settings → Database → Connection String (Transaction)
# 3. Adicionar no Railway
SUPABASE_URL=https://xyzabc.supabase.co
SUPABASE_SERVICE_ROLE_KEY=eyJhbGci...
# 4. Formato completo para SQLAlchemy
DATABASE_URL=postgresql+asyncpg://postgres:password@db.xyzabc.supabase.co:5432/postgres
4. Adicionar Redis (Railway Managed)
# Via Dashboard
# 1. New → Database → Add Redis
# 2. Railway auto-copia REDIS_URL para env vars
# 3. Verificar conectividade
# Via CLI
railway add redis
# Testar conexão
redis-cli -u $REDIS_URL ping
# Resposta esperada: PONG
5. Criar Serviços Worker e Beat
Railway inicialmente cria apenas o serviço web. Para adicionar worker e beat:
Via Dashboard
Passos detalhados:
- Dashboard → New Service
- "Create service from GitHub repo"
- Selecionar
cidadao.ai-backend - Settings → Deploy → Procfile Process: selecionar
worker(oubeat) - Settings → Variables: copiar todas as variáveis do serviço web
- Deploy: Railway executará o comando correspondente do Procfile
Via Railway CLI
# Criar serviço worker
railway service create --name cidadao-worker
# Criar serviço beat
railway service create --name cidadao-beat
# Configurar variáveis (copiar do serviço web)
railway variables copy --from web --to worker
railway variables copy --from web --to beat
📝 Procfile - Configuração dos Serviços
O Railway prioriza o Procfile sobre qualquer outro arquivo de configuração. Mantenha-o simples e limpo.
Procfile Completo
# Main API server - FastAPI com Uvicorn
# Usa $PORT injetado pelo Railway (geralmente 8000)
web: uvicorn src.api.app:app --host 0.0.0.0 --port $PORT --workers 4 --log-level info
# Celery worker para processamento assíncrono
# 5 queues por prioridade: critical, high, default, low, background
# 4 concurrency = 4 tasks simultâneas
worker: celery -A src.infrastructure.queue.celery_app worker --loglevel=info --queues=critical,high,default,low,background --concurrency=4 --max-tasks-per-child=1000
# Celery beat para tarefas agendadas
# Executa investigações automáticas a cada 6 horas
beat: celery -A src.infrastructure.queue.celery_app beat --loglevel=info
Detalhamento dos Comandos
Web Service
uvicorn src.api.app:app \
--host 0.0.0.0 \ # Aceita conexões de qualquer origem
--port $PORT \ # Porta dinâmica do Railway (NÃO hardcode!)
--workers 4 \ # 4 processos worker (CPU-bound)
--log-level info # Logs de nível INFO
Configurações de workers:
- Railway Hobby ($5/mês):
--workers 2 - Railway Pro ($20/mês):
--workers 4(atual) - Cálculo recomendado:
(2 x CPU_CORES) + 1
Worker Service
celery -A src.infrastructure.queue.celery_app worker \
--loglevel=info \ # Logs INFO
--queues=critical,high,default,low,background \ # 5 queues
--concurrency=4 \ # 4 tasks simultâneas
--max-tasks-per-child=1000 # Reciclar worker após 1000 tasks
Queues por prioridade:
- critical: Alertas, falhas críticas (SLA < 1min)
- high: Investigações urgentes (SLA < 5min)
- default: Análises padrão (SLA < 30min)
- low: Relatórios (SLA < 2h)
- background: Limpeza, manutenção (SLA < 24h)
Beat Service
celery -A src.infrastructure.queue.celery_app beat \
--loglevel=info # Logs INFO
Tarefas agendadas:
- Investigação automática: A cada 6 horas
- Limpeza de cache: Diariamente às 03:00 BRT
- Backup de métricas: A cada 12 horas
- Health check dos agentes: A cada 1 hora
⚙️ Configuração Avançada
Healthcheck Customizado
# railway.toml (opcional - apenas se precisar customizar healthcheck)
[deploy]
healthcheckPath = "/health"
healthcheckTimeout = 30
restartPolicyType = "ON_FAILURE"
restartPolicyMaxRetries = 3
Build Configuration
# nixpacks.toml (opcional - apenas se precisar customizar build)
[phases.setup]
nixPkgs = ["python310", "postgresql", "gcc"]
[phases.install]
cmds = ["pip install -r requirements.txt"]
[phases.build]
cmds = ["python -m compileall src/"]
[start]
cmd = "uvicorn src.api.app:app --host 0.0.0.0 --port $PORT"
Se você criar railway.toml ou nixpacks.toml, eles terão prioridade sobre o Procfile. Use apenas se necessário e teste extensivamente.
Runtime Customizado
# runtime.txt - Especifica versão exata do Python
python-3.10.12
Environment-Specific Variables
# Variáveis específicas do Railway (auto-injetadas)
RAILWAY_ENVIRONMENT # production, staging, development
RAILWAY_PROJECT_NAME # Nome do projeto
RAILWAY_SERVICE_NAME # Nome do serviço (web, worker, beat)
RAILWAY_DEPLOYMENT_ID # ID único do deploy
RAILWAY_GIT_COMMIT_SHA # SHA do commit atual
RAILWAY_GIT_BRANCH # Branch do Git
🔍 Monitoramento e Observabilidade
1. Logs em Tempo Real
Via Dashboard
Dashboard → Serviço → Logs
- Filtrar por severidade (INFO, WARNING, ERROR)
- Buscar por keyword
- Live tail (auto-scroll)
- Download logs (últimas 24h)
Via CLI
# Logs em tempo real (all services)
railway logs
# Logs de serviço específico
railway logs --service web
railway logs --service worker
railway logs --service beat
# Filtrar por severidade
railway logs --filter ERROR
# Últimas 100 linhas
railway logs --tail 100
2. Métricas Built-in
Dashboard → Metrics (disponível em todos os planos):
- CPU Usage (%)
- Memory Usage (MB/GB)
- Network Bandwidth (in/out)
- Request Rate (req/s)
- Response Time (p50, p95, p99 em ms)
- Error Rate (%)
3. Healthcheck Endpoint
# Endpoint de saúde da API
GET https://cidadao-api-production.up.railway.app/health
# Resposta esperada
{
"status": "healthy",
"timestamp": "2024-10-15T12:00:00Z",
"version": "2.1.0",
"environment": "production",
"services": {
"database": "ok",
"redis": "ok",
"agents": {
"total": 18,
"operational": 17,
"failed": 1
},
"celery": {
"worker": "ok",
"beat": "ok",
"queue_length": 5
}
},
"uptime": 604800,
"requests_processed": 1500000
}
4. Custom Metrics (Prometheus)
# src/infrastructu../monitoramento/metrics.py
from prometheus_client import Counter, Histogram, Gauge
# Request metrics
http_requests_total = Counter(
'http_requests_total',
'Total HTTP requests',
['method', 'endpoint', 'status']
)
http_request_duration = Histogram(
'http_request_duration_seconds',
'HTTP request duration',
['method', 'endpoint']
)
# Agent metrics
agent_investigations_total = Counter(
'agent_investigations_total',
'Total investigations by agent',
['agent_name', 'status']
)
# Celery metrics
celery_task_duration = Histogram(
'celery_task_duration_seconds',
'Celery task duration',
['task_name']
)
Endpoint de métricas:
GET https://cidadao-api-production.up.railway.app/metrics
# Formato Prometheus (pode ser ingerido por Grafana Cloud)
5. Integração com Grafana Cloud (Opcional)
# Variáveis para exportar métricas
GRAFANA_CLOUD_PROMETHEUS_URL=https://prometheus-prod-01-eu-west-0.grafana.net/api/prom/push
GRAFANA_CLOUD_PROMETHEUS_USER=123456
GRAFANA_CLOUD_PROMETHEUS_PASSWORD=eyJrI...
# Habilitar push de métricas
ENABLE_METRICS_PUSH=true
METRICS_PUSH_INTERVAL=60 # segundos
🚨 Troubleshooting
Problema 1: App Roda na Porta 7860 (Porta do HuggingFace)
Sintoma:
INFO: Uvicorn running on http://0.0.0.0:7860 # ❌ ERRADO
Causa: Railway está executando start_hf.py ou app.py ao invés do Procfile.
Solução:
# 1. Verificar arquivos conflitantes
ls railway.toml railway.json nixpacks.toml
# 2. Remover TODOS exceto Procfile
rm railway.toml railway.json nixpacks.toml
# 3. Commit e push
git add .
git commit -m "fix(deploy): force Railway to use Procfile"
git push origin main
# Railway fará novo deploy usando APENAS o Procfile
Problema 2: Deploy Falha com "Invalid PORT"
Sintoma:
Error: Invalid PORT value: undefined
Causa: Código hardcoded com porta fixa ou $PORT não sendo lido.
Solução:
# ❌ ERRADO
port = 7860
# ✅ CORRETO
import os
port = int(os.getenv("PORT", 8000))
Problema 3: Worker Não Inicia
Sintoma:
celery.exceptions.ImproperlyConfigured: Result backend must be configured
Causa: REDIS_URL não configurado.
Solução:
# Via Dashboard
New → Database → Add Redis → Railway auto-configura REDIS_URL
# Via CLI
railway add redis
# Verificar
railway variables list | grep REDIS_URL
Problema 4: Healthcheck Falha
Sintoma:
Health check failed: Connection refused
Causa: Aplicação não iniciou corretamente.
Soluções:
- Verificar logs:
railway logs --service web --tail 100
- Verificar variáveis obrigatórias:
railway variables list
# Confirmar: JWT_SECRET_KEY, SECRET_KEY, SUPABASE_URL
- Testar localmente:
# Simular ambiente Railway
export PORT=8000
uvicorn src.api.app:app --host 0.0.0.0 --port $PORT
Problema 5: Celery Beat Não Agenda Tasks
Sintoma: Tasks agendadas não executam.
Causa: Beat não está persistindo schedule.
Solução:
# Adicionar volume persistente (via Railway Dashboard)
# Settings → Volumes → Add volume
# Mount path: /data
# Atualizar Procfile para usar schedule persistente
beat: celery -A src.infrastructure.queue.celery_app beat --loglevel=info --schedule=/data/celerybeat-schedule
Problema 6: Out of Memory (OOM)
Sintoma:
Killed (memory exhausted)
Causa: Uso excessivo de memória (comum com muitos workers).
Solução:
- Reduzir workers:
web: uvicorn src.api.app:app --host 0.0.0.0 --port $PORT --workers 2 # era 4
worker: celery ... --concurrency=2 # era 4
- Upgrade do plano Railway:
Hobby ($5/mês): 512MB RAM
Pro ($20/mês): 8GB RAM ← Recomendado para produção
- Otimizar código:
# Liberar memória após tasks pesadas
import gc
gc.collect()
💰 Custos e Otimização
Estrutura de Custos Atual
| Item | Plano | Custo/mês | Detalhes |
|---|---|---|---|
| Railway Project | Pro | $20 | Execução ilimitada dos 3 serviços |
| Redis | Managed | $10 | 1GB, 99.9% uptime |
| PostgreSQL | Supabase Free | $0 | 500MB (upgrade: $25/mês para 8GB) |
| Domínio | Cloudflare | $0 | DNS gratuito |
| Total | - | $30/mês | Produção full-stack |
Otimizações de Custo
- Usar Hobby para Development:
# Projeto separado para staging/dev
Railway Hobby: $5/mês (500h execução)
- Reduzir workers em staging:
# staging/Procfile
web: uvicorn src.api.app:app --host 0.0.0.0 --port $PORT --workers 1
worker: celery ... --concurrency=1
# Sem beat em staging
- Cache agressivo:
# Aumentar TTL de cache em dev
CACHE_TTL=7200 # 2h (produção: 1h)
🔄 CI/CD Automático
Deploy Automático
Railway faz deploy automático em cada push para main:
GitHub Actions (Opcional)
Para CI/CD mais controlado, adicione GitHub Actions:
# .github/workflows/deploy-railway.yml
name: Deploy to Railway
on:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Install dependencies
run: pip install -r requirements.txt
- name: Run tests
run: pytest tests/ -v --cov=src/
- name: Type check
run: mypy src/
deploy:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Railway CLI
run: npm install -g @railway/cli
- name: Deploy to Railway
env:
RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
run: railway up
Rollback Manual
# Via Dashboard
Dashboard → Deployments → Selecionar deployment anterior → Redeploy
# Via CLI
railway rollback
📚 Recursos e Links Úteis
Documentação Oficial
Cidadão.AI
Comunidade
Consulte os logs via railway logs ou abra uma issue no repositório do backend.
Anterior: Guia de Deploy → Próximo: Configuração Docker →