fix(convex): mover cron jobs para API HTTP + crontab do Linux
Problema: - Cron jobs do Convex criam registros em _scheduled_job_logs - Convex self-hosted carrega TODAS as versoes em memoria - 1488 execucoes/dia = ~45k registros/mes acumulando - Uso de memoria chegando a 19GB, causando 12 OOM kills/dia Solucao: - Criar endpoints HTTP em /api/cron/* para substituir crons - Desabilitar crons no Convex (comentados em crons.ts) - Chamar endpoints via crontab do Linux Novos arquivos: - src/app/api/cron/chat-cleanup/route.ts - src/app/api/cron/usb-cleanup/route.ts - scripts-static/* (copiado da VPS para versionamento) Documentacao: - docs/OPERATIONS.md secao 12 com instrucoes do crontab 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
e2dde8510a
commit
178c7d7341
10 changed files with 1357 additions and 19 deletions
53
src/app/api/cron/chat-cleanup/route.ts
Normal file
53
src/app/api/cron/chat-cleanup/route.ts
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
import { NextRequest, NextResponse } from "next/server"
|
||||
|
||||
import { createConvexClient } from "@/server/convex-client"
|
||||
import { api } from "@/convex/_generated/api"
|
||||
|
||||
export const runtime = "nodejs"
|
||||
export const dynamic = "force-dynamic"
|
||||
|
||||
// Endpoint para encerrar sessoes de chat inativas
|
||||
// Substitui o cron job do Convex para evitar acumulo de registros em _scheduled_job_logs
|
||||
// Chamado via crontab do Linux:
|
||||
// * * * * * curl -s "https://tickets.esdrasrenan.com.br/api/cron/chat-cleanup" -H "x-cron-secret: $CRON_SECRET" >/dev/null 2>&1
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
// Verificar secret no header
|
||||
const authHeader = request.headers.get("x-cron-secret")
|
||||
const expectedSecret = process.env.CRON_SECRET || process.env.REPORTS_CRON_SECRET
|
||||
|
||||
if (!expectedSecret) {
|
||||
return NextResponse.json(
|
||||
{ error: "CRON_SECRET nao configurado no servidor" },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
|
||||
if (authHeader !== expectedSecret) {
|
||||
return NextResponse.json(
|
||||
{ error: "Nao autorizado" },
|
||||
{ status: 401 }
|
||||
)
|
||||
}
|
||||
|
||||
try {
|
||||
const convex = createConvexClient()
|
||||
const result = await convex.mutation(api.liveChat.autoEndInactiveSessions, {})
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: "Sessoes de chat inativas encerradas",
|
||||
result,
|
||||
timestamp: new Date().toISOString(),
|
||||
})
|
||||
} catch (error) {
|
||||
console.error("Erro ao executar chat-cleanup:", error)
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
53
src/app/api/cron/usb-cleanup/route.ts
Normal file
53
src/app/api/cron/usb-cleanup/route.ts
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
import { NextRequest, NextResponse } from "next/server"
|
||||
|
||||
import { createConvexClient } from "@/server/convex-client"
|
||||
import { api } from "@/convex/_generated/api"
|
||||
|
||||
export const runtime = "nodejs"
|
||||
export const dynamic = "force-dynamic"
|
||||
|
||||
// Endpoint para limpar policies USB pendentes
|
||||
// Substitui o cron job do Convex para evitar acumulo de registros em _scheduled_job_logs
|
||||
// Chamado via crontab do Linux:
|
||||
// */30 * * * * curl -s "https://tickets.esdrasrenan.com.br/api/cron/usb-cleanup" -H "x-cron-secret: $CRON_SECRET" >/dev/null 2>&1
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
// Verificar secret no header
|
||||
const authHeader = request.headers.get("x-cron-secret")
|
||||
const expectedSecret = process.env.CRON_SECRET || process.env.REPORTS_CRON_SECRET
|
||||
|
||||
if (!expectedSecret) {
|
||||
return NextResponse.json(
|
||||
{ error: "CRON_SECRET nao configurado no servidor" },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
|
||||
if (authHeader !== expectedSecret) {
|
||||
return NextResponse.json(
|
||||
{ error: "Nao autorizado" },
|
||||
{ status: 401 }
|
||||
)
|
||||
}
|
||||
|
||||
try {
|
||||
const convex = createConvexClient()
|
||||
const result = await convex.mutation(api.usbPolicy.cleanupStalePendingPolicies, {})
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: "Policies USB pendentes limpas",
|
||||
result,
|
||||
timestamp: new Date().toISOString(),
|
||||
})
|
||||
} catch (error) {
|
||||
console.error("Erro ao executar usb-cleanup:", error)
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue