# QueueMaster - Guia de Uso Completo

## Índice

- [Básico](#básico)
- [Listener de Comandos](#listener-de-comandos-obrigatório-por-host)
- [Intermediário](#intermediário)
- [Avançado](#avançado)

---

## Básico

### Iniciar o QueueMaster

#### Comando Padrão (Development)

```bash
# Usa configuração do ambiente local
php og queue-master
```

**O que acontece**:
1. Detecta ambiente = `development` (via `isLocal()`)
2. Lê vhost de `RABBITMQ_VHOST` ou `/DB_SERVER`
3. Cria supervisors configurados em `environments.development`
4. Inicia workers conforme `maxProcesses`

**Output esperado**:
```
Starting Queue Master for environment: development
Master name: server1-abc123
VHost: /tenant1
[INFO] Starting worker process: default:worker-12345
[INFO] Starting worker process: default:worker-12346
```

#### Especificar Ambiente

```bash
# Força ambiente production
php og queue-master --environment=production

# Ou via variável de ambiente
QUEUE_MASTER_ENV=production php og queue-master
```

#### Especificar VHost

```bash
# VHost específico
php og queue-master --vhost=/tenant1

# Combinar ambiente e vhost
php og queue-master --environment=production --vhost=/tenant2
```

### Listener de Comandos (obrigatório por host)

O autoscaling e os comandos manuais só são aplicados quando o listener `queue-master:listen-commands` está rodando no host local. Ele consome a fila `qm:command_queue:{hostname}` e dispara o `CommandExecutor`.

#### Desenvolvimento

```bash
# Executa em primeiro plano com logs verbosos a cada 5s
php og queue-master:listen-commands --poll-interval=5 --debug
```

- Ideal para depurar permissões (`sudo systemctl`) e validar se comandos estão chegando.
- Use `CTRL+C` para finalizar; o loop trata SIGTERM/SIGINT e fecha graciosamente.

#### Produção

```bash
# Executa em background (exemplo simples)
php og queue-master:listen-commands --poll-interval=3 >> /var/log/qm-listener.log 2>&1 &
```

Recomendações:
- Um listener por host/container que tenha workers gerenciados.
- Rodar com o mesmo usuário dos workers (geralmente `www-data`).
- Configurar restart automático via systemd/Supervisor para continuar após reboots/deploys.

#### Como verificar

```bash
# Processo ativo?
ps aux | grep 'queue-master:listen-commands' | grep -v grep

# Há backlog?
redis-cli LLEN qm:command_queue:$(hostname)
```

Esperado: pelo menos um processo ativo e `LLEN` próximo de zero. Se o backlog cresce, o listener não está consumindo.

#### Sintomas de listener inativo

- Dashboard mostra comandos “pendentes” e nenhum worker muda de estado.
- Autoscaling gera logs “Published command ...” sem o par “Marked ... as executed”.
- `redis-cli LRANGE qm:command_queue:{hostname} 0 -1` retorna dezenas de IDs.

Basta subir o listener: ele consumirá a fila acumulada e atualizará os status automaticamente.

### Ver Processos Rodando

#### Listar Todos os Processos

```bash
# Ver Master + Supervisors + Workers
ps aux | grep -E "queue-master|queue:work"
```

**Output esperado**:
```
user  12340  php og queue-master                     <- Master
user  12341  php og queue-master:supervisor default  <- Supervisor
user  12345  php og queue-master:work --queue=default <- Worker
user  12346  php og queue-master:work --queue=default <- Worker
```

#### Ver Apenas Workers

```bash
ps aux | grep "queue:work" | grep -v grep
```

#### Contar Workers Ativos

```bash
ps aux | grep "queue:work" | grep -v grep | wc -l
```

### Ver Logs

#### Logs de Workers

```bash
# Tempo real
tail -f docker/logs/worker/error.log

# Últimas 100 linhas
tail -n 100 docker/logs/worker/error.log

# Filtrar por PID
tail -f docker/logs/worker/error.log | grep "PID=12345"
```

#### Logs PHP

```bash
tail -f docker/logs/php/error.log
```

#### Logs da Aplicação

```bash
# Formato: _logs/{TENANT}/officegest-YYYY-MM-DD.log
tail -f _logs/og-tenant1.test:8003/officegest-$(date +%Y-%m-%d).log
```

#### Filtrar Logs por Tipo

```bash
# Apenas erros
tail -f docker/logs/worker/error.log | grep ERROR

# Apenas shutdowns
tail -f docker/logs/worker/error.log | grep "stopping"

# Worker específico
tail -f docker/logs/worker/error.log | grep "worker-12345"
```

### Parar o QueueMaster

#### Graceful Shutdown (Recomendado)

```bash
# Encontrar PID do Master
ps aux | grep "queue-master" | grep -v "queue-master:work" | grep -v grep

# Enviar SIGTERM
kill -SIGTERM <master_pid>

# Ou SIGINT
kill -SIGINT <master_pid>
```

**O que acontece**:
1. Master seta `working = false`
2. Master envia `terminate()` para todos supervisors
3. Supervisors enviam `SIGTERM` para todos workers
4. Workers aguardam job atual terminar
5. Workers fazem cleanup e exit(0)
6. Supervisors aguardam workers (até 20s)
7. Master remove registro do Redis
8. Master exit(0)

#### Force Kill (Não Recomendado)

```bash
# Mata imediatamente (pode perder jobs)
kill -9 <master_pid>
```

**Consequências**:
- Jobs em execução são perdidos
- Workers órfãos podem ficar no sistema
- Locks no Redis podem não ser liberados

### Verificar Saúde do Sistema

#### Check Rápido

```bash
# Master está vivo?
ps aux | grep "queue-master" | grep -v grep

# Quantos workers?
ps aux | grep "queue:work" | grep -v grep | wc -l

# Uso de memória total
ps aux | grep -E "queue-master|queue:work" | awk '{sum+=$6} END {print sum/1024 " MB"}'
```

#### Dashboard Web

```bash
# Acesse no navegador
# URL: https://og-{tenant}.test:8003/queue-master/dashboard

# Ou via curl
curl https://og-tenant1.test:8003/api/queue-master/overview
```

---

## Intermediário

### Uso com VHosts Customizados

#### Cenário: Múltiplos Tenants

Você tem 3 tenants e quer workers isolados:

```bash
# Terminal 1: Tenant 1
RABBITMQ_VHOST=/tenant1 php og queue-master &

# Terminal 2: Tenant 2
RABBITMQ_VHOST=/tenant2 php og queue-master &

# Terminal 3: Tenant 3
RABBITMQ_VHOST=/tenant3 php og queue-master &
```

**Verificar isolamento**:
```bash
ps aux | grep queue-master | grep -v grep | awk '{print $2, $NF}'
```

Output:
```
12340 --vhost=/tenant1
12350 --vhost=/tenant2
12360 --vhost=/tenant3
```

#### Script de Inicialização Multi-Tenant

Crie `start-queuemaster-all.sh`:

```bash
#!/bin/bash

TENANTS=("tenant1" "tenant2" "tenant3")

for tenant in "${TENANTS[@]}"; do
    echo "Starting QueueMaster for $tenant..."
    RABBITMQ_VHOST=/$tenant php og queue-master > /dev/null 2>&1 &
    echo "Started with PID $!"
done

echo "All QueueMasters started"
ps aux | grep queue-master | grep -v grep
```

### Monitoramento via Dashboard

#### Acessar Dashboard

```
URL: https://og-tenant1.test:8003/queue-master/dashboard
```

#### Endpoints da API

```bash
# Overview geral
curl https://og-tenant1.test:8003/api/queue-master/overview

# Workers ativos
curl https://og-tenant1.test:8003/api/queue-master/workers

# Filas
curl https://og-tenant1.test:8003/api/queue-master/queues

# Jobs ativos
curl https://og-tenant1.test:8003/api/queue-master/jobs/active

# Histórico de shutdowns
curl https://og-tenant1.test:8003/api/queue-master/shutdowns/history

# Tenant switches
curl https://og-tenant1.test:8003/api/queue-master/tenant-switches
```

#### Filtrar Dados

```bash
# Shutdowns com filtros
curl "https://og-tenant1.test:8003/api/queue-master/shutdowns/history?limit=10&hostname=server1&queue=default"

# Jobs ativos com limite
curl "https://og-tenant1.test:8003/api/queue-master/jobs/active?limit=50"

# Tenant switches recentes
curl "https://og-tenant1.test:8003/api/queue-master/tenant-switches?limit=20&hostname=server1"
```

### Interpretar Métricas

#### Overview

```json
{
  "total_workers": 10,
  "processing_workers": 3,
  "idle_workers": 7,
  "total_jobs_processed": 1542,
  "total_memory_mb": 512.5,
  "queues_count": 3,
  "total_queue_size": 42,
  "avg_queue_pressure": 1.4
}
```

**Interpretação**:
- `processing_workers` / `total_workers` = taxa de utilização (30%)
- `avg_queue_pressure` < 2.0 = sistema saudável
- `avg_queue_pressure` > 5.0 = considere aumentar workers

#### Workers

```json
{
  "pid": 12345,
  "status": "processing",
  "memory_usage_mb": 45.2,
  "jobs_processed": 67,
  "uptime_human": "25m 30s",
  "current_job": "App\\Jobs\\SendEmailJob"
}
```

**Sinais de Problemas**:
- `memory_usage_mb` próximo do limite = pode reciclar logo
- `uptime_human` muito alto = worker não está reciclando
- `status = "error"` = investigar logs

#### Queues

```json
{
  "name": "default",
  "messages": 42,
  "consumers": 5,
  "pressure": 8.4,
  "pressure_status": "high"
}
```

**Pressure Status**:
- `low` (< 2.0): Sistema ocioso
- `medium` (2.0-5.0): Carga normal
- `high` (5.0-10.0): Considere mais workers
- `critical` (> 10.0): URGENTE - adicione workers

### Comandos Úteis de Diagnóstico

#### Verificar Conectividade RabbitMQ

```bash
# Testar conexão manual
php og queue:work default --once --vhost=/tenant1
```

Se funcionar, QueueMaster também funcionará.

#### Listar Filas no RabbitMQ

```bash
# Via rabbitmqadmin (se disponível)
rabbitmqadmin list queues vhost=/tenant1

# Via Management API
curl -u guest:guest http://localhost:15672/api/queues/%2Ftenant1
```

#### Verificar Redis

```bash
# Ver workers registrados
redis-cli KEYS "queuemaster:workers:*"

# Ver jobs ativos
redis-cli KEYS "queuemaster:jobs:active:*"

# Ver shutdowns
redis-cli ZRANGE queuemaster:shutdowns:history 0 -1 WITHSCORES
```

#### Monitorar CPU e Memória

```bash
# Top dos processos QueueMaster
ps aux | grep -E "queue-master|queue:work" | grep -v grep | \
  awk '{print $2, $3, $4, $11}' | column -t

# Saída:
# PID    CPU%  MEM%  COMMAND
# 12340  0.1   0.5   queue-master
# 12345  5.2   2.1   queue:work
# 12346  3.8   1.9   queue:work
```

---

## Avançado

### Tuning de Performance

#### Identificar Bottlenecks

**Sintoma 1: Fila crescendo infinitamente**

```bash
# Verificar tamanho da fila
curl https://og-tenant1.test:8003/api/queue-master/queues | jq '.data.queues[] | {name, messages, consumers, pressure}'
```

**Solução**:
1. Aumentar `maxProcesses` na configuração
2. Habilitar autoscaling (`balance: 'auto'`)
3. Otimizar jobs (melhorar código)

**Sintoma 2: Workers reciclam muito rápido**

```bash
# Ver histórico de shutdowns
curl https://og-tenant1.test:8003/api/queue-master/shutdowns/history?limit=50 | \
  jq '.data.shutdowns[] | {reason, uptime_seconds}'
```

Se `uptime_seconds` < 60s consistentemente:

**Solução**:
```php
// Aumentar limites
'workerMaxTime' => 600,   // Era 300
'memory'        => 1024,  // Era 512
```

**Sintoma 3: Jobs timeout frequentemente**

```bash
# Ver jobs falhados
curl https://og-tenant1.test:8003/api/queue-master/jobs/failed?limit=20 | \
  jq '.data.jobs[] | {job_class, exception_message}'
```

Se aparecer "Job timeout exceeded":

**Solução**:
```php
'timeout' => 300,  // Era 60
```

#### Otimização de Autoscaling

**Cenário**: Fila com carga variável (picos em horários específicos)

```php
'environments' => [
    'production' => [
        'default' => [
            'balance'       => 'auto',
            'minProcesses'  => 2,     // Mínimo sempre ativo
            'maxProcesses'  => 20,    // Permite escalar bastante
            'workerMaxTime' => 300,
            'memory'        => 512,
        ],
    ],
],

'autoscaling' => [
    'enabled'              => true,
    'cooldown'             => 5,      // Espera 5s entre ajustes
    'maxShift'             => 2,      // Adiciona/remove 2 por vez
    'scale_up_threshold'   => 2.0,    // Mais agressivo (era 3.0)
    'scale_down_threshold' => 0.5,    // Mais conservador (era 1.0)
],
```

**Raciocínio**:
- `scale_up_threshold = 2.0`: Escala rápido em picos
- `scale_down_threshold = 0.5`: Demora a desescalar (evita flapping)
- `maxShift = 2`: Reage mais rápido a mudanças

#### Multi-Queue Configuration Avançada

**Cenário**: 3 tipos de jobs com diferentes prioridades

```php
'environments' => [
    'production' => [
        // Alta prioridade: emails, notificações
        'high' => [
            'queue'         => 'high',
            'balance'       => 'auto',
            'maxProcesses'  => 10,
            'minProcesses'  => 3,      // Sempre 3 ativos
            'workerMaxTime' => 300,
            'timeout'       => 30,     // Jobs rápidos
            'memory'        => 256,
        ],

        // Prioridade normal: processamento geral
        'default' => [
            'queue'         => 'default',
            'balance'       => 'auto',
            'maxProcesses'  => 5,
            'minProcesses'  => 1,
            'workerMaxTime' => 300,
            'timeout'       => 60,
            'memory'        => 512,
        ],

        // Baixa prioridade: jobs pesados
        'low' => [
            'queue'         => 'low',
            'balance'       => 'simple',  // Scaling mais conservador
            'maxProcesses'  => 3,
            'minProcesses'  => 1,
            'workerMaxTime' => 1800,      // 30 min
            'timeout'       => 600,       // 10 min por job
            'memory'        => 1024,
        ],
    ],
],
```

### Troubleshooting de Problemas Comuns

#### Workers não pegam jobs

**Diagnóstico**:

```bash
# 1. Workers estão rodando?
ps aux | grep "queue:work" | wc -l

# 2. Fila tem mensagens?
curl https://og-tenant1.test:8003/api/queue-master/queues | \
  jq '.data.queues[] | select(.name == "default") | .messages'

# 3. VHost está correto?
ps aux | grep "queue:work" | grep vhost
```

**Causas Comuns**:

1. **VHost errado**
   ```bash
   # Worker: --vhost=/tenant1
   # Job enviado para: /tenant2
   ```
   Solução: Verificar consistência de vhosts

2. **Queue name errado**
   ```php
   // Job configurado para queue "emails"
   // Worker ouvindo queue "default"
   ```
   Solução: Alinhar configuração

3. **RabbitMQ connection issue**
   ```bash
   # Testar conexão
   php og queue:work default --once --vhost=/tenant1
   ```

#### Workers morrem inesperadamente

**Diagnóstico**:

```bash
# Ver razões de shutdown
curl https://og-tenant1.test:8003/api/queue-master/shutdowns/stats | jq

# Ver shutdowns anômalos
curl https://og-tenant1.test:8003/api/queue-master/shutdowns/anomalous | jq
```

**Causas por Shutdown Reason**:

| Reason | Causa Provável | Solução |
|--------|----------------|---------|
| `memory_limit` | Jobs consomem muita RAM | Aumentar `memory` config |
| `max_time_reached` | Workers demoram muito | Aumentar `workerMaxTime` |
| `fatal_error` | Bug no código do job | Investigar stack trace |
| `signal_sigterm` | Kill manual ou OOM Killer | Verificar memória do host |

**Investigar Fatal Errors**:

```bash
# Filtrar logs por fatal error
tail -n 1000 docker/logs/worker/error.log | grep -A 10 "fatal_error"

# Ver stack trace completo
tail -n 5000 docker/logs/worker/error.log | grep -B 5 -A 20 "Fatal error"
```

#### Problemas de Memória

**Sintoma**: Workers reciclam frequentemente com `memory_limit`

**Diagnóstico**:

```bash
# Ver uso de memória dos workers
curl https://og-tenant1.test:8003/api/queue-master/workers | \
  jq '.data.workers[] | {pid, memory_usage_mb, memory_limit_mb: (.memory_limit / 1024 / 1024)}'
```

**Soluções**:

1. **Aumentar limite**:
   ```php
   'memory' => 1024,  // Era 512
   ```

2. **Reduzir maxJobs** (força reciclagem mais cedo):
   ```php
   'maxJobs' => 50,  // Era 0 (ilimitado)
   ```

3. **Otimizar jobs**:
   ```php
   // No job, liberar recursos grandes
   public function handle()
   {
       $largeData = $this->processData();

       // Liberar memória explicitamente
       unset($largeData);
       gc_collect_cycles();
   }
   ```

#### Problemas de Tenant Switching

**Diagnóstico**:

```bash
# Ver tenant switches problemáticos
curl https://og-tenant1.test:8003/api/queue-master/tenant-switches/problematic?limit=50 | jq
```

**Causas Comuns**:

1. **Job sem domain()**:
   ```php
   // Job não implementa domain()
   public function domain(): ?string
   {
       return null;  // PROBLEMA!
   }
   ```

   Solução:
   ```php
   public function domain(): ?string
   {
       return $this->tenant;
   }
   ```

2. **Context não persiste**:
   Verificar se job serializa corretamente tenant info.

### Workers Zumbis/Órfãos

**Sintoma**: Workers no Redis mas processo morto

**Diagnóstico**:

```bash
# Workers no Redis
redis-cli KEYS "queuemaster:workers:*" | wc -l

# Workers no sistema
ps aux | grep "queue:work" | grep -v grep | wc -l

# Se Redis > Sistema = órfãos
```

**Limpeza Manual**:

```bash
# Listar órfãos
redis-cli KEYS "queuemaster:workers:*" | while read key; do
    pid=$(echo $key | grep -oP '\d+$')
    if ! ps -p $pid > /dev/null 2>&1; then
        echo "Orphan: $key (PID $pid not running)"
        redis-cli DEL "$key"
    fi
done
```

**Prevenção**:

O Master limpa órfãos automaticamente a cada 60s, mas você pode forçar:

```bash
# Restart do Master força cleanup
kill -SIGUSR2 <master_pid>
```

### Scripts Úteis de Automação

#### Script de Health Check

Crie `queuemaster-health.sh`:

```bash
#!/bin/bash

echo "=== QueueMaster Health Check ==="

# 1. Master está vivo?
MASTER_PID=$(ps aux | grep "queue-master" | grep -v "queue-master:work" | grep -v grep | awk '{print $2}')
if [ -z "$MASTER_PID" ]; then
    echo "ERROR: Master not running!"
    exit 1
else
    echo "OK: Master running (PID $MASTER_PID)"
fi

# 2. Quantos workers?
WORKER_COUNT=$(ps aux | grep "queue:work" | grep -v grep | wc -l)
echo "OK: $WORKER_COUNT workers active"

# 3. Memória total
TOTAL_MEM=$(ps aux | grep -E "queue-master|queue:work" | grep -v grep | awk '{sum+=$6} END {print sum/1024}')
echo "OK: Total memory: ${TOTAL_MEM} MB"

# 4. Verificar filas
QUEUE_SIZE=$(curl -s https://og-tenant1.test:8003/api/queue-master/queues | jq '.data.queues[0].messages')
echo "OK: Default queue size: $QUEUE_SIZE"

# 5. Pressure
PRESSURE=$(curl -s https://og-tenant1.test:8003/api/queue-master/queues | jq '.data.queues[0].pressure')
if (( $(echo "$PRESSURE > 10" | bc -l) )); then
    echo "WARNING: High queue pressure: $PRESSURE"
else
    echo "OK: Queue pressure: $PRESSURE"
fi

echo "=== Health Check Complete ==="
```

#### Script de Restart Seguro

Crie `queuemaster-safe-restart.sh`:

```bash
#!/bin/bash

echo "=== Safe QueueMaster Restart ==="

# 1. Encontrar Master PID
MASTER_PID=$(ps aux | grep "queue-master" | grep -v "queue-master:work" | grep -v grep | awk '{print $2}')

if [ -z "$MASTER_PID" ]; then
    echo "No master running, starting fresh..."
    php og queue-master &
    exit 0
fi

echo "Found Master PID: $MASTER_PID"

# 2. Enviar SIGTERM (graceful)
echo "Sending SIGTERM..."
kill -SIGTERM $MASTER_PID

# 3. Aguardar até 60s
echo "Waiting for graceful shutdown (max 60s)..."
for i in {1..60}; do
    if ! ps -p $MASTER_PID > /dev/null 2>&1; then
        echo "Master stopped gracefully after ${i}s"
        break
    fi
    sleep 1
done

# 4. Verificar se ainda está vivo
if ps -p $MASTER_PID > /dev/null 2>&1; then
    echo "WARNING: Master still alive, force killing..."
    kill -9 $MASTER_PID
    sleep 2
fi

# 5. Limpar workers órfãos
echo "Cleaning up orphaned workers..."
ps aux | grep "queue:work" | grep -v grep | awk '{print $2}' | xargs -r kill -9

# 6. Restart
echo "Starting QueueMaster..."
php og queue-master &

echo "=== Restart Complete ==="
```

### Debug Avançado

#### Ativar Modo Debug

```php
// Worker options
'debug' => true,
```

Ou via variável de ambiente:
```bash
QUEUE_WORKER_DEBUG=true php og queue-master
```

**Output adicional**:
- Cada job processado
- Tenant switches detalhados
- Memory usage após cada job
- Heartbeats

#### Rastrear Job Específico

```bash
# 1. Pegar job_id do dashboard
JOB_ID="550e8400-e29b-41d4-a716-446655440000"

# 2. Buscar em todos os logs
grep -r "$JOB_ID" docker/logs/
grep -r "$JOB_ID" _logs/

# 3. Verificar no Redis
redis-cli GET "queuemaster:jobs:active:$JOB_ID"
```

## Próximos Documentos

- **[EXAMPLES.md](EXAMPLES.md)** - Exemplos práticos completos
- **[API_REFERENCE.md](API_REFERENCE.md)** - Referência completa da API
- **[MONITORING.md](MONITORING.md)** - Monitoramento detalhado
- **[TROUBLESHOOTING.md](TROUBLESHOOTING.md)** - Resolução de problemas específicos
