Eu queria rodar tarefas periódicas no macOS, mas a configuração do launchd continua difícil de entender, então resolvi usar PM2 como caminho mais simples.
Configuração para rodar um job Cron com PM2
cd $PROJECT_ROOT
pm2 ecosystemA configuração é gerenciada em ecosystem.config.cjs.
module.exports = { apps: [ { name: "cronJob", script: "main.ts", interpreter: "~/.bun/bin/bun", // número de instâncias é 1 instances: 1, // executar a cada 15 minutos cron_restart: "*/15 * * * *", exec_mode: "fork", // reiniciar automaticamente quando arquivos mudarem: não watch: false, // reinício automático: não autorestart: false, }, ],};Pontos
- cron_restart: define o intervalo no formato cron
- autorestart: false: como o processo roda como job agendado, o reinício automático fica desligado
- interpreter: permite especificar qualquer runtime, incluindo Bun
Comando de inicialização:
pm2 start ecosystem.config.cjs
pm2 saveExemplo de implementação do job
Um processo que obtém o IP periodicamente e grava em banco.
import { Database } from 'bun:sqlite';
const DDL = `CREATE TABLE IF NOT EXISTS ip_history ( id INTEGER PRIMARY KEY AUTOINCREMENT, ip TEXT NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP);`
async function fetchIpConfig() { const response = await fetch("https://ifconfig.io/ip").catch((err) => new Error(err)); if (response instanceof Error || !response.ok) { return null; }
const ip = await response.text();
return ip;}
async function main() { const ip = await fetchIpConfig(); if (ip == null) return;
using db = new Database('ip-monitor.sqlite', { create: true }); db.exec(DDL); using query = db.query("INSERT INTO ip_history (ip) VALUES ($ip);"); query.run({ $ip: ip });}
await main();Referências
- PM2 - Ecosystem File
- PM2でCronジョブを作成する方法 | NullNull
- How to make a task job with PM2? - Stack Overflow
Resumo
Com PM2, dá para gerenciar jobs agendados com uma configuração bem mais simples que launchd.
Definindo o job em ecosystem.config.cjs, também fica fácil aproveitar os recursos de gerenciamento de processo do PM2 para logs e reinícios quando necessário.
hsb.horse