Skip to content

CloudSQL no Slack Bot - Guia de Configuração

✅ Migração Completa

O slack_bot.py foi atualizado para usar os novos serviços CloudSQL:

  • CloudSQLSessionService - Sessões ativas com TTL
  • CloudSQLMemoryService - Memórias de longo prazo
  • OpenMemoryService - Removido (substituído)
  • DatabaseSessionService - Removido (substituído)

📋 Variáveis de Ambiente Necessárias

CloudSQL (Obrigatórias)

# Credenciais (OBRIGATÓRIAS)
CLOUDSQL_USER=seu_usuario
CLOUDSQL_PASSWORD=sua_senha

# Configuração do banco (padrões mostrados)
CLOUDSQL_HOST=127.0.0.1              # Ou IP da instância CloudSQL
CLOUDSQL_PORT=3306                    # Porta MySQL
CLOUDSQL_DATABASE=ifriend_agent_db    # Nome do banco

# Para Cloud Run / GKE (opcional - tem precedência sobre TCP)
CLOUDSQL_UNIX_SOCKET=/cloudsql/PROJECT:REGION:INSTANCE

# Tempo de expiração das sessões (padrão: 60 minutos)
SESSION_TTL_MINUTES=60

Outras Variáveis do Bot

# Slack
SLACK_BOT_TOKEN=xoxb-...
SLACK_SIGNING_SECRET=...

# App Config
APP_NAME=ifriend-agente-atendimento
APP_PORT=8080

# Vertex AI (se usado)
GOOGLE_CLOUD_PROJECT=seu-projeto-gcp
GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account-key.json

🔧 Setup Inicial

1. Criar as Tabelas

Execute o script de setup:

cd ifriend_agent/session
python setup_cloudsql_sessions.py

cd ../memory
python setup_cloudsql.py

Ou manualmente:

-- Tabela de Sessões
CREATE TABLE agent_sessions (
    id VARCHAR(255) PRIMARY KEY,
    app_name VARCHAR(255) NOT NULL,
    user_id VARCHAR(255) NOT NULL,
    messages JSON,
    start_time DATETIME NOT NULL,
    last_activity_time DATETIME NOT NULL,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    expires_at DATETIME NOT NULL,
    INDEX idx_app_user (app_name, user_id),
    INDEX idx_last_activity (last_activity_time),
    INDEX idx_expires_at (expires_at)
);

-- Tabela de Memórias
CREATE TABLE agent_memories (
    id VARCHAR(255) PRIMARY KEY,
    app_name VARCHAR(255) NOT NULL,
    user_id VARCHAR(255) NOT NULL,
    session_id VARCHAR(255) NOT NULL,
    messages JSON NOT NULL,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_app_user (app_name, user_id),
    INDEX idx_session (session_id),
    INDEX idx_created_at (created_at)
);

2. Configurar Variáveis de Ambiente

Desenvolvimento Local:

# .env
CLOUDSQL_USER=root
CLOUDSQL_PASSWORD=sua_senha_dev
CLOUDSQL_HOST=127.0.0.1
CLOUDSQL_PORT=3306
CLOUDSQL_DATABASE=ifriend_agent_db
SESSION_TTL_MINUTES=60

SLACK_BOT_TOKEN=xoxb-...
SLACK_SIGNING_SECRET=...
APP_NAME=ifriend-agente-atendimento
APP_PORT=8080

Cloud Run / GKE (Produção):

# Unix Socket (recomendado)
CLOUDSQL_UNIX_SOCKET=/cloudsql/meu-projeto:us-central1:minha-instancia
CLOUDSQL_USER=ifriend_bot
CLOUDSQL_PASSWORD=senha_segura_prod
CLOUDSQL_DATABASE=ifriend_agent_db
SESSION_TTL_MINUTES=120  # 2 horas em produção

# Ou TCP (menos recomendado)
CLOUDSQL_HOST=10.123.45.67  # IP privado
CLOUDSQL_PORT=3306

3. Iniciar o Bot

python slack_bot.py

🧪 Testando a Integração

Verificar Inicialização

Ao iniciar, deve ver:

🔧 Configurando CloudSQL Services...
   Database: ifriend_agent_db
   Connection: TCP (127.0.0.1:3306)
   Session TTL: 60min
✅ CloudSQLSessionService inicializado
✅ CloudSQLMemoryService inicializado
✅ Runner configurado com CloudSQL Session + Memory Services

Verificar Salvamento de Sessões

Ao interagir com o bot:

💾 [Callback] Salvando sessão <session_id> na memória (usuário: U12345, eventos: 4)...
✅ [Callback] Sessão <session_id> salva com sucesso no CloudSQL Memory

Queries de Teste

-- Ver sessões ativas
SELECT 
    id, 
    app_name, 
    user_id,
    start_time,
    last_activity_time,
    expires_at,
    TIMESTAMPDIFF(MINUTE, NOW(), expires_at) as minutes_remaining
FROM agent_sessions
WHERE expires_at > NOW()
ORDER BY last_activity_time DESC;

-- Ver memórias recentes
SELECT 
    id, 
    app_name, 
    user_id, 
    session_id,
    JSON_LENGTH(messages) as message_count,
    created_at
FROM agent_memories
ORDER BY created_at DESC
LIMIT 10;

-- Buscar memórias por usuário
SELECT 
    session_id,
    JSON_LENGTH(messages) as messages,
    created_at
FROM agent_memories
WHERE user_id = 'U12345'
ORDER BY created_at DESC;

🎯 Como Funciona

Fluxo de Sessão

  1. Usuário envia mensagem no Slack
  2. CloudSQLSessionService.get_session() busca/cria sessão
  3. Sessão tem TTL de 60 minutos (configurável)
  4. Cada mensagem atualiza last_activity_time
  5. Sessões expiradas são automaticamente limpas

Fluxo de Memória

  1. Após cada resposta do agent
  2. auto_save_session_to_memory_callback() é chamado
  3. CloudSQLMemoryService.add_session_to_memory() salva permanentemente
  4. Memórias nunca expiram - histórico completo
  5. ADK pode buscar memórias com memory_service.search_memory()

Diferença entre Session e Memory

┌─────────────────────────────────────────────────────────┐
│                    CONVERSA ATIVA                       │
│                                                         │
│  CloudSQLSessionService                                 │
│  ├── Armazena: Sessão atual (thread Slack)            │
│  ├── TTL: 60 minutos (expira após inatividade)        │
│  ├── Propósito: Contexto da conversa em andamento     │
│  └── Tabela: agent_sessions                           │
└─────────────────────────────────────────────────────────┘
                        │
                        │ auto_save_session_to_memory_callback
                        │
                        ▼
┌─────────────────────────────────────────────────────────┐
│                  HISTÓRICO PERMANENTE                   │
│                                                         │
│  CloudSQLMemoryService                                  │
│  ├── Armazena: Todas as conversas (histórico)         │
│  ├── TTL: Nunca expira                                 │
│  ├── Propósito: Conhecimento de longo prazo           │
│  └── Tabela: agent_memories                           │
└─────────────────────────────────────────────────────────┘

🔍 Monitoramento

Logs Importantes

# Sucesso
"✅ CloudSQLSessionService inicializado"
"✅ CloudSQLMemoryService inicializado"
"✅ [Callback] Sessão {id} salva com sucesso no CloudSQL Memory"

# Erros
"❌ CLOUDSQL_USER e CLOUDSQL_PASSWORD são obrigatórias!"
"❌ Erro ao inicializar CloudSQLSessionService: {erro}"
"❌ [Callback] Erro ao salvar sessão na memória: {erro}"

Health Checks

# Testar conexão com CloudSQL
from ifriend_agent.session import CloudSQLSessionService

service = CloudSQLSessionService(
    host="127.0.0.1",
    port=3306,
    database="ifriend_agent_db",
    user="root",
    password="senha"
)

# Deve conectar sem erro
sessions = await service.list_sessions(app_name="test")
print(f"Conexão OK - {len(sessions)} sessões encontradas")

🚀 Deploy

Cloud Build

Atualizar cloudbuild.slack.yaml:

substitutions:
  _CLOUDSQL_CONNECTION_NAME: "meu-projeto:us-central1:minha-instancia"
  _CLOUDSQL_DATABASE: "ifriend_agent_db"
  _SESSION_TTL_MINUTES: "120"

steps:
  # ... build steps ...

  - name: 'gcr.io/cloud-builders/gcloud'
    args:
      - 'run'
      - 'deploy'
      - 'ifriend-slack-bot'
      - '--image=gcr.io/$PROJECT_ID/ifriend-slack-bot:$SHORT_SHA'
      - '--platform=managed'
      - '--region=us-central1'
      - '--add-cloudsql-instances=${_CLOUDSQL_CONNECTION_NAME}'
      - '--set-env-vars=CLOUDSQL_UNIX_SOCKET=/cloudsql/${_CLOUDSQL_CONNECTION_NAME}'
      - '--set-env-vars=CLOUDSQL_DATABASE=${_CLOUDSQL_DATABASE}'
      - '--set-env-vars=SESSION_TTL_MINUTES=${_SESSION_TTL_MINUTES}'
      - '--set-secrets=CLOUDSQL_USER=cloudsql-user:latest'
      - '--set-secrets=CLOUDSQL_PASSWORD=cloudsql-password:latest'

Secret Manager

# Criar secrets
echo -n "ifriend_bot" | gcloud secrets create cloudsql-user --data-file=-
echo -n "senha_segura_prod" | gcloud secrets create cloudsql-password --data-file=-

# Dar permissão ao Cloud Run
gcloud secrets add-iam-policy-binding cloudsql-user \
  --member="serviceAccount:PROJECT_NUMBER-compute@developer.gserviceaccount.com" \
  --role="roles/secretmanager.secretAccessor"

gcloud secrets add-iam-policy-binding cloudsql-password \
  --member="serviceAccount:PROJECT_NUMBER-compute@developer.gserviceaccount.com" \
  --role="roles/secretmanager.secretAccessor"

📊 Performance

Latência Esperada

CloudSQL (mesma região):
- get_session(): ~5-10ms
- append_event(): ~5-10ms
- add_session_to_memory(): ~10-20ms
- search_memory(): ~20-50ms (depende do tamanho)

OpenMemory (comparação):
- add_memory(): ~100-200ms (HTTP externo)
- search_memory(): ~200-500ms (embedding + busca)

CloudSQL é 5-10x mais rápido!

Otimizações

  1. Connection Pool: CloudSQL mantém pool de conexões
  2. Índices: Tabelas tem índices em campos chave
  3. JSON Nativo: MySQL 5.7+ suporta JSON otimizado
  4. TTL Automático: Limpeza de sessões expiradas
  5. Unix Socket: Melhor performance no Cloud Run/GKE

❓ Troubleshooting

"CLOUDSQL_USER e CLOUDSQL_PASSWORD são obrigatórias!"

Configure as variáveis:

export CLOUDSQL_USER=seu_usuario
export CLOUDSQL_PASSWORD=sua_senha

"Table 'agent_sessions' doesn't exist"

Execute o setup:

cd ifriend_agent/session
python setup_cloudsql_sessions.py

"Can't connect to MySQL server"

Verifique:

  1. CloudSQL está rodando
  2. IP está correto (CLOUDSQL_HOST)
  3. Firewall permite conexão
  4. Credenciais estão corretas

Cloud Run/GKE: Use Unix Socket:

CLOUDSQL_UNIX_SOCKET=/cloudsql/PROJECT:REGION:INSTANCE

Sessões não expiram

Verifique se o TTL está configurado:

export SESSION_TTL_MINUTES=60  # Padrão

Limpar manualmente:

DELETE FROM agent_sessions WHERE expires_at < NOW();

Memórias não são salvas

Verifique os logs:

# Deve aparecer: [Callback] Sessão {id} salva com sucesso no CloudSQL Memory

# Se não aparecer, verifique: [Callback] Erro ao salvar sessão na memória: {erro}

Testar manualmente:

await memory_service.add_session_to_memory(session)

✨ Conclusão

Agora seu Slack Bot usa CloudSQL para tudo:

✅ Sessões ativas → agent_sessions (com TTL)
✅ Memórias permanentes → agent_memories (sem TTL)
✅ Performance 5-10x melhor que antes
✅ Sem dependências externas (OpenMemory)
✅ Totalmente compatível com ADK

Pronto para produção! 🚀