Skip to content

Tareas Programadas (Cron)

Las tareas programadas te permiten ejecutar código de forma recurrente usando expresiones cron. Son ideales para limpieza de datos, generación de reportes, sincronización y monitoreo.

Conceptos clave

  • @cron({ name, cron, disabled? }): registra una clase como tarea cron.
  • ICronHandler: interfaz con handle() y opcionalmente handleError().
  • runCronHandlers([]): activa el scheduler de tareas cron.

Paso 1: Definir una tarea cron

import { cron, ICronHandler } from '@wabot-dev/framework'
@cron({
name: 'daily-cleanup',
cron: '0 2 * * *', // Todos los días a las 2:00 AM
})
export class DailyCleanupHandler implements ICronHandler {
constructor(private cleanupService: CleanupService) {}
async handle() {
await this.cleanupService.removeExpiredSessions()
await this.cleanupService.archiveOldRecords()
}
async handleError(error: any) {
console.error('Error en limpieza diaria:', error)
// Notificar al equipo, enviar alerta, etc.
}
}

Paso 2: Expresiones cron

Referencia rápida del formato cron (5 campos):

┌───────────── minuto (0-59)
│ ┌───────────── hora (0-23)
│ │ ┌───────────── día del mes (1-31)
│ │ │ ┌───────────── mes (1-12)
│ │ │ │ ┌───────────── día de la semana (0-7, 0 y 7 = domingo)
│ │ │ │ │
* * * * *
ExpresiónDescripción
* * * * *Cada minuto
*/5 * * * *Cada 5 minutos
0 * * * *Cada hora (minuto 0)
0 9 * * *Todos los días a las 9:00 AM
0 2 * * *Todos los días a las 2:00 AM
0 9 * * 1Cada lunes a las 9:00 AM
0 9 * * 1-5Lunes a viernes a las 9:00 AM
0 0 1 * *Primer día de cada mes a medianoche
0 9,18 * * *A las 9:00 AM y 6:00 PM

Paso 3: Deshabilitar temporalmente

Puedes deshabilitar una tarea sin eliminarla usando disabled: true:

@cron({
name: 'heavy-report',
cron: '0 3 * * 0', // Domingos a las 3:00 AM
disabled: true, // Deshabilitado temporalmente
})
export class HeavyReportHandler implements ICronHandler {
async handle() {
// No se ejecutará hasta que disabled sea false
}
}

Paso 4: Activar el scheduler

import { runCronHandlers } from '@wabot-dev/framework'
runCronHandlers([
DailyCleanupHandler,
WeeklyReportHandler,
OfferExpiryChecker,
])

Ejemplo completo

Tareas de mantenimiento para un bot de ventas:

import { cron, ICronHandler, singleton, runCronHandlers } from '@wabot-dev/framework'
// --- Limpieza diaria ---
@cron({
name: 'expire-old-offers',
cron: '0 0 * * *', // Medianoche
})
export class ExpireOffersHandler implements ICronHandler {
constructor(private offerRepository: OfferRepository) {}
async handle() {
const activeOffers = await this.offerRepository.findActiveOffers()
for (const offer of activeOffers) {
if (offer.isExpired) {
offer.updateStatus('expired', 'Vencida automáticamente')
await this.offerRepository.update(offer)
}
}
}
async handleError(error: any) {
console.error('Error expirando ofertas:', error)
}
}
// --- Reporte semanal ---
@cron({
name: 'weekly-sales-report',
cron: '0 9 * * 1', // Lunes a las 9:00 AM
})
export class WeeklySalesReportHandler implements ICronHandler {
constructor(
private offerRepository: OfferRepository,
private reportService: ReportService,
) {}
async handle() {
const lastWeek = new Date()
lastWeek.setDate(lastWeek.getDate() - 7)
const accepted = await this.offerRepository.findAcceptedInDateRange(
lastWeek.toISOString(),
new Date().toISOString(),
)
const totalRevenue = accepted.reduce((sum, offer) => sum + offer.totalPrice, 0)
await this.reportService.generate({
period: 'weekly',
totalOffers: accepted.length,
totalRevenue,
generatedAt: new Date().toISOString(),
})
}
}
// --- Seguimiento de prospectos inactivos ---
@cron({
name: 'inactive-prospect-followup',
cron: '0 10 * * 1-5', // Lunes a viernes a las 10:00 AM
})
export class InactiveProspectFollowUpHandler implements ICronHandler {
constructor(
private prospectRepository: ProspectRepository,
private async: Async,
) {}
async handle() {
const inactive = await this.prospectRepository.findInactiveProspects(3)
for (const prospect of inactive) {
await this.async.runCommand(SendNotificationCommand, {
prospectId: prospect.id,
type: 'followup',
message: 'Hola, hace unos días conversamos sobre nuestras soluciones. ¿Tienes alguna pregunta?',
})
}
}
}
// --- Registro ---
runCronHandlers([
ExpireOffersHandler,
WeeklySalesReportHandler,
InactiveProspectFollowUpHandler,
])

Siguiente paso

Aprende a configurar tu aplicación con variables de entorno: Variables de Entorno.