Jobs em background sem pagar por execução: Trigger.dev + Coolify

Como rodamos os jobs do PideAí com Trigger.dev self-hosted no Coolify e deploy pelo GitHub Actions: retries, cron e logs, com custo fixo.

2 min de leitura

Compartilhar WhatsAppLinkedInX
Ilustração de servidores conectados a um painel com tarefas agendadas, sincronização e alertas

Quanto vai custar o cron de amanhã? Se seus jobs rodam num serviço que cobra por execução, você só descobre quando a fatura chega.

Todo backend chega nesse ponto: tem trabalho que não pode esperar um usuário clicar. No PideAí eram três coisas: sincronizar a taxa de câmbio, enviar lembretes por WhatsApp e limpar carrinhos abandonados.

As duas saídas de sempre

A primeira é montar na mão: Redis, uma fila, workers, retries e algo que avise quando falha. Funciona, mas agora você mantém mais uma peça de infraestrutura.

A segunda é pagar um serviço gerenciado. Você não mantém nada, mas cada execução soma: um job a cada 30 minutos são 1.440 execuções por mês, e isso é um só.

Queríamos controle total, pouca manutenção e um custo que não mexe. Encontramos em Trigger.dev self-hosted + Coolify + GitHub Actions.

O que o Trigger.dev resolve

O Trigger.dev é um framework open source para escrever, rodar e monitorar jobs em TypeScript. Já vem com o que, de outro jeito, você acabaria construindo: tenta de novo as tarefas que falham, agenda com cron, guarda os logs de cada execução e deixa uma tarefa disparar outra para montar fluxos completos.

Além disso, dá para hospedar você mesmo. Os dados ficam no seu servidor e você não paga por execução: paga o servidor, que já tinha.

Exemplo real: a taxa do BCV, a cada hora

O PideAí vende na Venezuela, então os preços dependem da taxa do Banco Central da Venezuela. Esta tarefa busca a taxa a cada hora e atualiza a loja:

import { schedules } from '@trigger.dev/sdk/v3';

export const syncExchangeRates = schedules.task({
  id: 'sync-bcv-rates',
  cron: '0 * * * *', // a cada hora
  run: async () => {
    const rates = await fetchBCVRates();
    await updateStoreRates(rates);
    console.log('Exchange rates synced successfully.');
  },
});

Se o BCV não responde, o Trigger.dev tenta de novo sozinho, e no painel você vê cada execução com o resultado.

Como chega em produção

Diagrama: um git push dispara npx trigger.dev deploy; o Coolify provisiona e gerencia o Trigger.dev, cujos workers processam a fila de jobs: taxas de câmbio a cada hora, limpeza de sessões diária e campanhas de WhatsApp agendadas

A instância do Trigger.dev (a API e os workers) roda no Coolify, uma alternativa open source e self-hosted ao Heroku ou à Vercel. Lá a gente sobe e gerencia como qualquer outro app do servidor.

O deploy fica com o GitHub Actions: cada push na main roda npx trigger.dev deploy e os jobs se atualizam sem ninguém mexer em nada. A URL da API e o token ficam como secrets do repositório, então o deploy sempre aponta para a nossa instância e não para a nuvem do Trigger.dev.

O que mais roda lá

Além da taxa de câmbio:

  • Limpeza de sessões expiradas, uma vez por dia.
  • Alertas de estoque baixo, a cada 30 minutos.
  • Campanhas de WhatsApp agendadas.

Para adicionar um job novo basta escrever a tarefa e dar push, e a fatura continua igual.

Serve para você?

Se você já tem um servidor e roda mais do que um punhado de jobs, provavelmente sim. Se não quer administrar nada, um serviço gerenciado continua sendo razoável: o que você paga é não ter que manter.