Módulo 5: Scheduling y Tiempo

Mini-Proyecto: Workflow Diario/Semanal Complejo

Descripción de la cápsula

Cierre del módulo. Vas a construir un workflow productivo que integra todos los conceptos de M05: scheduling preciso con cron, timezone correctamente, business days con holidays, y verificación de DST. Caso: reporte ejecutivo semanal que se manda lunes a las 9am hora CDMX, excepto si es holiday (entonces el siguiente día hábil).


Lo que vas a aprender

  • Integrar scheduling avanzado, timezone, business days, holidays
  • Diseñar workflows resilientes a edge cases temporales
  • Generar reporte semanal profesional

El escenario

Requirements

  • Workflow se dispara lunes 9am hora CDMX
  • Si el lunes es holiday, NO ejecutar (esperar al siguiente día hábil)
  • Generar reporte de la semana pasada (lunes-domingo de la semana anterior)
  • Datos:
    • Total ventas del periodo (mock con Sheet)
    • Nuevos clientes (mock)
    • Top 3 productos vendidos
  • Output: Slack con reporte formateado

Paso 1: Setup

1.1. Sheet de holidays

Crear holidays_mx con feriados mexicanos 2026 (también deja algunos lunes específicos):

date
2026-01-01
2026-02-02
2026-03-16  ← lunes
2026-05-01
2026-09-16
2026-11-16  ← lunes
2026-12-25

1.2. Sheet de ventas (mock data)

Crear sales_2026 con: date, product, amount, customer_email. Llena con ~50 filas distribuidas en abril-mayo 2026.


Paso 2: Workflow

2.1. Trigger

Schedule Trigger:
- Cron: 0 9 * * 1   (lunes 9am)
- Timezone: America/Mexico_City

2.2. Verificar si es holiday

[Schedule]
   │
[Sheet: leer holidays_mx]
   │
[Set: verificar]
  - today_date: {{ DateTime.now().setZone('America/Mexico_City').toFormat('yyyy-MM-dd') }}
  - is_holiday: {{ $('Sheet holidays').all().some(h => h.json.date === DateTime.now().setZone('America/Mexico_City').toFormat('yyyy-MM-dd')) }}
   │
[IF: !is_holiday]
├─ TRUE → continuar
└─ FALSE → [Slack: "Hoy es holiday, reporte se generará mañana"] → fin

2.3. Si no es holiday — alternativa con re-schedule

Para realmente "esperar al siguiente día hábil", podríamos:

  1. Si es holiday → terminar
  2. Otro workflow (con Schedule tuesday-friday 9am) verifica si el lunes anterior fue holiday Y el reporte no se generó → generar

Para simplificar este proyecto: si lunes es holiday, simplemente saltar esa semana. En producción real, implementarías el catch-up.

2.4. Calcular semana anterior

[Set: calcular fechas]
  - week_end: {{ DateTime.now().setZone('America/Mexico_City').minus({days: 1}).toFormat('yyyy-MM-dd') }}  // domingo pasado
  - week_start: {{ DateTime.now().setZone('America/Mexico_City').minus({days: 7}).toFormat('yyyy-MM-dd') }}  // lunes hace 7 días

2.5. Leer ventas de la semana

[Google Sheets: sales_2026]
- Filter: date entre week_start y week_end

2.6. Calcular stats

[Aggregate: all into 'sales']
   │
[Set: stats]
  - total_sales: {{ $json.sales.length }}
  - total_amount: {{ $json.sales.reduce((a, b) => a + Number(b.amount), 0) }}

  - unique_customers: {{ [...new Set($json.sales.map(v => v.customer_email))].length }}

  - top_products: {{
    Object.entries(
      $json.sales.reduce((acc, v) => {
        acc[v.product] = (acc[v.product] || 0) + 1;
        return acc;
      }, {})
    )
    .sort((a, b) => b[1] - a[1])
    .slice(0, 3)
    .map(([prod, count]) => `• ${prod}: ${count}`)
    .join('\n')
  }}

2.7. Enviar reporte

[Slack]
📊 *Reporte Semanal*
Semana: {{ $json.week_start }} a {{ $json.week_end }}

*Resumen:*
• Total operaciones: {{ $json.total_sales }}
• Monto total: ${{ $json.total_amount.toFixed(2) }}
• Clientes únicos: {{ $json.unique_customers }}

*Top 3 productos:*
{{ $json.top_products }}

_Generado: {{ DateTime.now().setZone('America/Mexico_City').setLocale('es').toFormat("EEEE dd 'de' MMMM 'a las' HH:mm") }}_

Paso 3: Test

3.1. Test manual (sin esperar lunes)

Agregar Manual Trigger en paralelo al Schedule. Ejecutar manualmente.

Verifica:

  • Datos del Sheet filtrados correctamente por fecha
  • Stats calculadas correctamente
  • Slack recibe mensaje formateado

3.2. Test holiday

Modifica el Sheet de holidays para incluir HOY (lo que sea). Ejecuta. Debe terminar con "es holiday, saltando".

Remueve y vuelve a ejecutar. Debe procesar normal.

3.3. Verificar timezone

Compara los timestamps en el reporte con tu reloj real (CDMX). Deberían coincidir.


Variantes opcionales

Variante 1: Catch-up automático

Si el lunes fue holiday, el martes verificar si el reporte ya se generó. Si no, generarlo retroactivamente.

[Schedule martes-viernes 9am]
   │
[IF: lunes anterior fue holiday AND reporte no se ha generado]
└─ TRUE → ejecutar lógica del reporte con fechas de la semana anterior

Variante 2: Reporte mensual

Mismo concepto pero el primer día hábil del mes:

[Schedule día 1-3 del mes 9am]
   │
[IF: hoy es primer día hábil del mes]
└─ procesar reporte mensual

Variante 3: Multi-timezone

Si tu equipo está en CDMX, Madrid, y Buenos Aires, generar 3 reportes en los 3 horarios locales.


Resumen y siguiente paso

Lo que construiste:

  • Workflow real con scheduling complejo y consciente de holidays
  • Manejo de timezone correcto
  • Cálculos de fechas precisos

Lo que sabes:

  • Aplicar cron + timezone + holidays
  • Calcular fechas relativas con Luxon
  • Manejar edge cases del calendario

Antes de pasar a M06:

  • Workflow funciona en test y reporta correctamente
  • Maneja holidays sin fallar
  • Reporte llega a Slack con formato profesional

Lo que sigue (Módulo 6 — Error Handling Básico):

Workflows productivos fallan. APIs caen, datos vienen malformados, credenciales expiran. M06 te enseña los patrones básicos de error handling: retry strategies, fallback paths, On Error connectors, y diseño defensivo.

(Error handling avanzado — try/catch sofisticado, dead letter queues — va en G10.)


Creado: Mayo 11, 2026 Versión: 1.0