Logon8n中文教程

定时任务与Cron

掌握N8N中的定时任务配置,实现精确的时间控制和调度管理

定时任务与Cron

定时任务是自动化工作流的重要组成部分。无论是每日报表生成、定期数据同步,还是监控检查,精确的时间控制都是关键。本章将深入讲解 N8N 中的各种定时机制。

⏰ 定时触发器概览

触发器类型对比

触发器类型适用场景精确度配置复杂度推荐使用
Cron复杂时间规则分钟级高频、精确任务
Schedule简单重复任务分钟级日常定时任务
Interval固定间隔执行秒级监控、轮询
Manual手动触发即时测试、临时任务

📅 Cron 表达式详解

Cron 语法结构

// Cron 表达式格式:分 时 日 月 周
// * * * * *
// │ │ │ │ │
// │ │ │ │ └── 星期几 (0-6, 0=周日)
// │ │ │ └──── 月份 (1-12)
// │ │ └────── 日期 (1-31)  
// │ └──────── 小时 (0-23)
// └────────── 分钟 (0-59)

常用 Cron 表达式

// 基础时间表达式
"0 9 * * *"          // 每天上午9点
"30 14 * * *"        // 每天下午2:30
"0 0 * * *"          // 每天午夜
"0 12 * * 0"         // 每周日中午12点

// 工作日表达式
"0 9 * * 1-5"        // 工作日上午9点
"30 18 * * 1-5"      // 工作日下午6:30
"0 8 * * MON,WED,FRI" // 周一、三、五上午8点

// 月度表达式
"0 0 1 * *"          // 每月1号午夜
"0 9 15 * *"         // 每月15号上午9点
"0 0 L * *"          // 每月最后一天午夜

// 季度和年度表达式
"0 9 1 1,4,7,10 *"   // 每季度第一天上午9点
"0 0 1 1 *"          // 每年1月1号午夜

// 高频执行表达式
"*/5 * * * *"        // 每5分钟执行一次
"0 */2 * * *"        // 每2小时执行一次
"*/15 9-17 * * 1-5"  // 工作日9-17点,每15分钟执行

高级 Cron 表达式

// 复杂业务场景
"0 9 1-7 * 1"        // 每月第一个周一上午9点
"0 0 1,15 * *"       // 每月1号和15号午夜
"30 2 * * *"         // 每天凌晨2:30(避开高峰期)
"0 6 * * 1"          // 每周一早上6点(周报)
"0 22 * * 0"         // 每周日晚上10点(备份)

// 特殊字符使用
"0 9-17/2 * * 1-5"   // 工作日9-17点,每2小时
"15,45 * * * *"      // 每小时的15分和45分
"0 9 1,15,L * *"     // 每月1号、15号和最后一天

// 避开特定时间
"0 9 * * 1-5"        // 工作日(排除周末)
"0 9 2-31 * *"       // 每月2号开始(避开月初处理)

🔧 Schedule 触发器配置

基础配置界面

// Schedule 触发器可视化配置
Rule: {
  "interval": [{
    "field": "cronExpression",
    "value": "0 9 * * 1-5"  // 工作日上午9点
  }]
}

// 时区设置
Timezone: "Asia/Shanghai"  // 中国标准时间
Timezone: "UTC"            // 协调世界时
Timezone: "America/New_York" // 美国东部时间

动态调度配置

// Function 节点:动态生成 Cron 表达式
function generateDynamicCron(businessConfig) {
  const { frequency, timeOfDay, daysOfWeek, timezone } = businessConfig;
  
  switch (frequency) {
    case 'daily':
      return `${timeOfDay.minute} ${timeOfDay.hour} * * *`;
      
    case 'weekdays':
      return `${timeOfDay.minute} ${timeOfDay.hour} * * 1-5`;
      
    case 'weekly':
      const dayNumbers = daysOfWeek.map(day => {
        const dayMap = { 'SUN': 0, 'MON': 1, 'TUE': 2, 'WED': 3, 'THU': 4, 'FRI': 5, 'SAT': 6 };
        return dayMap[day];
      }).join(',');
      return `${timeOfDay.minute} ${timeOfDay.hour} * * ${dayNumbers}`;
      
    case 'monthly':
      return `${timeOfDay.minute} ${timeOfDay.hour} 1 * *`;
      
    case 'custom':
      return businessConfig.customCron;
      
    default:
      throw new Error(`Unsupported frequency: ${frequency}`);
  }
}

// 业务配置示例
const businessConfigs = [
  {
    name: '每日销售报表',
    frequency: 'daily',
    timeOfDay: { hour: 9, minute: 0 },
    timezone: 'Asia/Shanghai'
  },
  {
    name: '工作日库存检查',
    frequency: 'weekdays', 
    timeOfDay: { hour: 8, minute: 30 },
    timezone: 'Asia/Shanghai'
  },
  {
    name: '周报生成',
    frequency: 'weekly',
    daysOfWeek: ['MON'],
    timeOfDay: { hour: 10, minute: 0 },
    timezone: 'Asia/Shanghai'
  }
];

// 生成所有配置的 Cron 表达式
const cronConfigs = businessConfigs.map(config => ({
  ...config,
  cronExpression: generateDynamicCron(config)
}));

console.log('生成的定时任务配置:', cronConfigs);
return [{ json: { configs: cronConfigs } }];

🔄 Interval 触发器精确控制

基础间隔配置

// Interval 节点配置
Interval: 5
Unit: "minutes"  // seconds, minutes, hours

// 等价的 Cron 表达式
"*/5 * * * *"   // 每5分钟

智能间隔调整

// Function 节点:动态调整执行间隔
const currentHour = new Date().getHours();
const dayOfWeek = new Date().getDay();

let intervalMinutes;

// 根据时间段调整执行频率
if (currentHour >= 9 && currentHour < 18) {
  // 工作时间:高频监控
  intervalMinutes = 5;
} else if (currentHour >= 18 && currentHour < 22) {
  // 晚间时间:中频监控
  intervalMinutes = 15;
} else {
  // 深夜时间:低频监控
  intervalMinutes = 60;
}

// 周末调整
if (dayOfWeek === 0 || dayOfWeek === 6) {
  intervalMinutes *= 2; // 周末降低频率
}

// 特殊业务时间调整
const specialEvents = getSpecialEvents(new Date());
if (specialEvents.isPromotionDay) {
  intervalMinutes = Math.floor(intervalMinutes / 2); // 促销日增加频率
}

function getSpecialEvents(date) {
  // 检查特殊业务事件
  const events = {
    isPromotionDay: false,
    isBlackFriday: false,
    isHoliday: false
  };
  
  // 双11促销检查
  if (date.getMonth() === 10 && date.getDate() === 11) {
    events.isPromotionDay = true;
  }
  
  // 黑色星期五检查
  if (date.getMonth() === 10 && date.getDay() === 5 && date.getDate() > 22) {
    events.isBlackFriday = true;
  }
  
  return events;
}

console.log(`当前执行间隔: ${intervalMinutes} 分钟`);

return [{
  json: {
    nextInterval: intervalMinutes,
    adjustmentReason: `工作时间段调整 (${currentHour}:00)`,
    timestamp: new Date().toISOString()
  }
}];

📊 定时任务监控

执行状态跟踪

// Function 节点:定时任务执行监控
class ScheduleMonitor {
  constructor() {
    this.staticData = $node.getWorkflowStaticData('global');
    this.executionHistory = this.staticData.executionHistory || [];
    this.maxHistorySize = 100;
  }
  
  recordExecution(taskName, success, duration, details = {}) {
    const executionRecord = {
      taskName: taskName,
      executionId: $execution.id,
      timestamp: new Date().toISOString(),
      success: success,
      duration: duration, // 毫秒
      details: details,
      nodeEnv: $env.NODE_ENV || 'unknown'
    };
    
    this.executionHistory.unshift(executionRecord);
    
    // 保持历史记录大小限制
    if (this.executionHistory.length > this.maxHistorySize) {
      this.executionHistory = this.executionHistory.slice(0, this.maxHistorySize);
    }
    
    this.staticData.executionHistory = this.executionHistory;
    
    console.log(`任务执行记录: ${taskName} - ${success ? '成功' : '失败'} (${duration}ms)`);
  }
  
  getExecutionStats(taskName = null, hoursBack = 24) {
    const cutoffTime = new Date(Date.now() - hoursBack * 60 * 60 * 1000);
    
    let relevantExecutions = this.executionHistory.filter(exec => 
      new Date(exec.timestamp) > cutoffTime
    );
    
    if (taskName) {
      relevantExecutions = relevantExecutions.filter(exec => 
        exec.taskName === taskName
      );
    }
    
    const totalExecutions = relevantExecutions.length;
    const successfulExecutions = relevantExecutions.filter(exec => exec.success).length;
    const failedExecutions = totalExecutions - successfulExecutions;
    
    const durations = relevantExecutions
      .filter(exec => exec.success && exec.duration)
      .map(exec => exec.duration);
    
    const avgDuration = durations.length > 0 
      ? durations.reduce((sum, d) => sum + d, 0) / durations.length 
      : 0;
    
    const maxDuration = durations.length > 0 ? Math.max(...durations) : 0;
    const minDuration = durations.length > 0 ? Math.min(...durations) : 0;
    
    return {
      taskName: taskName || 'all_tasks',
      timeRange: `${hoursBack}h`,
      totalExecutions: totalExecutions,
      successfulExecutions: successfulExecutions,
      failedExecutions: failedExecutions,
      successRate: totalExecutions > 0 ? (successfulExecutions / totalExecutions * 100).toFixed(2) + '%' : '0%',
      avgDuration: Math.round(avgDuration),
      maxDuration: maxDuration,
      minDuration: minDuration,
      lastExecution: relevantExecutions.length > 0 ? relevantExecutions[0] : null
    };
  }
  
  checkHealthStatus() {
    const stats = this.getExecutionStats();
    const recentStats = this.getExecutionStats(null, 1); // 最近1小时
    
    const health = {
      status: 'healthy',
      issues: [],
      recommendations: []
    };
    
    // 检查成功率
    const successRate = parseFloat(stats.successRate);
    if (successRate < 90) {
      health.status = 'warning';
      health.issues.push(`总体成功率较低: ${stats.successRate}`);
    }
    
    const recentSuccessRate = parseFloat(recentStats.successRate);
    if (recentSuccessRate < 80) {
      health.status = 'critical';
      health.issues.push(`最近成功率严重下降: ${recentStats.successRate}`);
    }
    
    // 检查执行频率
    if (recentStats.totalExecutions === 0) {
      health.status = 'warning';
      health.issues.push('最近1小时无执行记录');
    }
    
    // 检查执行时间
    if (stats.avgDuration > 300000) { // 5分钟
      health.status = 'warning';
      health.issues.push(`平均执行时间过长: ${stats.avgDuration}ms`);
      health.recommendations.push('考虑优化任务性能或分解复杂任务');
    }
    
    // 检查连续失败
    const recentFailures = this.getConsecutiveFailures();
    if (recentFailures >= 3) {
      health.status = 'critical';
      health.issues.push(`连续失败 ${recentFailures} 次`);
      health.recommendations.push('立即检查任务配置和依赖服务');
    }
    
    return {
      ...health,
      stats: stats,
      recentStats: recentStats,
      checkTime: new Date().toISOString()
    };
  }
  
  getConsecutiveFailures() {
    let consecutiveFailures = 0;
    
    for (const execution of this.executionHistory) {
      if (!execution.success) {
        consecutiveFailures++;
      } else {
        break;
      }
    }
    
    return consecutiveFailures;
  }
}

// 使用监控器
const monitor = new ScheduleMonitor();

// 记录当前任务执行
const taskStartTime = Date.now();
const taskName = $json.taskName || 'unknown_task';

try {
  // 执行主要任务逻辑
  const taskResult = await executeMainTask($json);
  
  const duration = Date.now() - taskStartTime;
  monitor.recordExecution(taskName, true, duration, {
    recordsProcessed: taskResult.recordsProcessed,
    dataSource: taskResult.dataSource
  });
  
  // 检查健康状态
  const healthStatus = monitor.checkHealthStatus();
  
  return [{
    json: {
      taskResult: taskResult,
      monitoring: {
        execution: {
          duration: duration,
          success: true
        },
        health: healthStatus
      }
    }
  }];
  
} catch (error) {
  const duration = Date.now() - taskStartTime;
  monitor.recordExecution(taskName, false, duration, {
    error: error.message,
    errorType: error.constructor.name
  });
  
  throw error;
}

async function executeMainTask(inputData) {
  // 模拟主要任务逻辑
  await new Promise(resolve => setTimeout(resolve, 1000));
  
  return {
    recordsProcessed: 150,
    dataSource: 'primary_db',
    completedAt: new Date().toISOString()
  };
}

性能分析和优化

// Function 节点:定时任务性能分析
class SchedulePerformanceAnalyzer {
  constructor() {
    this.staticData = $node.getWorkflowStaticData('global');
    this.performanceData = this.staticData.performanceData || {
      taskMetrics: {},
      systemMetrics: [],
      optimizationSuggestions: []
    };
  }
  
  analyzeTaskPerformance(taskName, executionData) {
    if (!this.performanceData.taskMetrics[taskName]) {
      this.performanceData.taskMetrics[taskName] = {
        executionCount: 0,
        totalDuration: 0,
        durations: [],
        memoryUsage: [],
        cpuUsage: [],
        errorCount: 0,
        lastAnalysis: null
      };
    }
    
    const metrics = this.performanceData.taskMetrics[taskName];
    
    // 更新基础指标
    metrics.executionCount++;
    metrics.totalDuration += executionData.duration;
    metrics.durations.push(executionData.duration);
    
    if (executionData.memoryUsage) {
      metrics.memoryUsage.push(executionData.memoryUsage);
    }
    
    if (executionData.error) {
      metrics.errorCount++;
    }
    
    // 保持最近100次执行的数据
    if (metrics.durations.length > 100) {
      metrics.durations = metrics.durations.slice(-100);
      metrics.memoryUsage = metrics.memoryUsage.slice(-100);
    }
    
    // 计算性能统计
    const stats = this.calculatePerformanceStats(metrics);
    
    // 生成优化建议
    const suggestions = this.generateOptimizationSuggestions(taskName, stats);
    
    metrics.lastAnalysis = {
      timestamp: new Date().toISOString(),
      stats: stats,
      suggestions: suggestions
    };
    
    this.staticData.performanceData = this.performanceData;
    
    return {
      taskName: taskName,
      performance: stats,
      suggestions: suggestions
    };
  }
  
  calculatePerformanceStats(metrics) {
    const durations = metrics.durations;
    const avgDuration = durations.reduce((sum, d) => sum + d, 0) / durations.length;
    const maxDuration = Math.max(...durations);
    const minDuration = Math.min(...durations);
    
    // 计算百分位数
    const sortedDurations = [...durations].sort((a, b) => a - b);
    const p50 = sortedDurations[Math.floor(sortedDurations.length * 0.5)];
    const p90 = sortedDurations[Math.floor(sortedDurations.length * 0.9)];
    const p95 = sortedDurations[Math.floor(sortedDurations.length * 0.95)];
    
    // 计算趋势
    const recentDurations = durations.slice(-10);
    const oldDurations = durations.slice(-20, -10);
    const recentAvg = recentDurations.reduce((sum, d) => sum + d, 0) / recentDurations.length;
    const oldAvg = oldDurations.length > 0 
      ? oldDurations.reduce((sum, d) => sum + d, 0) / oldDurations.length 
      : recentAvg;
    
    const trend = recentAvg > oldAvg * 1.1 ? 'degrading' : 
                  recentAvg < oldAvg * 0.9 ? 'improving' : 'stable';
    
    return {
      executionCount: metrics.executionCount,
      avgDuration: Math.round(avgDuration),
      maxDuration: maxDuration,
      minDuration: minDuration,
      p50Duration: p50,
      p90Duration: p90,
      p95Duration: p95,
      errorRate: (metrics.errorCount / metrics.executionCount * 100).toFixed(2) + '%',
      trend: trend,
      recentAvgDuration: Math.round(recentAvg),
      performanceScore: this.calculatePerformanceScore(avgDuration, metrics.errorCount / metrics.executionCount)
    };
  }
  
  calculatePerformanceScore(avgDuration, errorRate) {
    // 性能评分算法 (0-100)
    let score = 100;
    
    // 执行时间影响 (超过30秒开始扣分)
    if (avgDuration > 30000) {
      score -= Math.min(40, (avgDuration - 30000) / 1000);
    }
    
    // 错误率影响
    score -= errorRate * 50;
    
    return Math.max(0, Math.round(score));
  }
  
  generateOptimizationSuggestions(taskName, stats) {
    const suggestions = [];
    
    // 执行时间优化建议
    if (stats.avgDuration > 60000) {
      suggestions.push({
        type: 'performance',
        priority: 'high',
        message: '执行时间过长,建议分解为多个子任务或优化算法',
        details: `平均执行时间 ${stats.avgDuration}ms 超过建议值 60s`
      });
    }
    
    if (stats.p95Duration > stats.avgDuration * 2) {
      suggestions.push({
        type: 'performance',
        priority: 'medium', 
        message: '执行时间波动较大,检查是否存在性能瓶颈',
        details: `P95执行时间 ${stats.p95Duration}ms 是平均值的 ${(stats.p95Duration / stats.avgDuration).toFixed(1)} 倍`
      });
    }
    
    // 错误率优化建议
    const errorRate = parseFloat(stats.errorRate);
    if (errorRate > 5) {
      suggestions.push({
        type: 'reliability',
        priority: 'high',
        message: '错误率过高,需要改进错误处理和重试机制',
        details: `当前错误率 ${stats.errorRate} 超过建议值 5%`
      });
    }
    
    // 趋势优化建议
    if (stats.trend === 'degrading') {
      suggestions.push({
        type: 'trend',
        priority: 'medium',
        message: '性能呈下降趋势,建议检查数据量增长和系统资源',
        details: `最近执行时间 ${stats.recentAvgDuration}ms 比历史平均值有所增长`
      });
    }
    
    // 调度优化建议
    if (stats.avgDuration > 300000) {
      suggestions.push({
        type: 'scheduling',
        priority: 'medium',
        message: '执行时间很长,考虑调整到系统低峰期执行',
        details: '建议将任务安排在凌晨或业务低峰期'
      });
    }
    
    return suggestions;
  }
  
  generatePerformanceReport() {
    const report = {
      generatedAt: new Date().toISOString(),
      summary: {
        totalTasks: Object.keys(this.performanceData.taskMetrics).length,
        healthyTasks: 0,
        warningTasks: 0,
        criticalTasks: 0
      },
      taskAnalysis: [],
      recommendations: []
    };
    
    // 分析每个任务
    for (const [taskName, metrics] of Object.entries(this.performanceData.taskMetrics)) {
      const analysis = metrics.lastAnalysis;
      if (analysis) {
        const stats = analysis.stats;
        let status = 'healthy';
        
        if (stats.performanceScore < 60 || parseFloat(stats.errorRate) > 10) {
          status = 'critical';
          report.summary.criticalTasks++;
        } else if (stats.performanceScore < 80 || parseFloat(stats.errorRate) > 5) {
          status = 'warning';
          report.summary.warningTasks++;
        } else {
          report.summary.healthyTasks++;
        }
        
        report.taskAnalysis.push({
          taskName: taskName,
          status: status,
          performanceScore: stats.performanceScore,
          avgDuration: stats.avgDuration,
          errorRate: stats.errorRate,
          trend: stats.trend,
          suggestions: analysis.suggestions
        });
        
        // 收集所有建议
        report.recommendations.push(...analysis.suggestions.map(s => ({
          ...s,
          taskName: taskName
        })));
      }
    }
    
    // 按优先级排序建议
    report.recommendations.sort((a, b) => {
      const priorityOrder = { 'high': 3, 'medium': 2, 'low': 1 };
      return priorityOrder[b.priority] - priorityOrder[a.priority];
    });
    
    return report;
  }
}

// 使用性能分析器
const analyzer = new SchedulePerformanceAnalyzer();

const taskPerformance = analyzer.analyzeTaskPerformance($json.taskName, {
  duration: $json.executionDuration,
  memoryUsage: process.memoryUsage ? process.memoryUsage().heapUsed : null,
  error: $json.error || null
});

const performanceReport = analyzer.generatePerformanceReport();

console.log(`任务性能分析完成: ${taskPerformance.performance.performanceScore}/100 分`);

return [{
  json: {
    taskPerformance: taskPerformance,
    overallReport: performanceReport
  }
}];

🌍 时区处理

多时区任务管理

// Function 节点:多时区定时任务管理
class TimezoneManager {
  constructor() {
    this.businessTimezones = {
      'CN': 'Asia/Shanghai',      // 中国
      'US': 'America/New_York',   // 美国东部
      'EU': 'Europe/London',      // 欧洲
      'JP': 'Asia/Tokyo',         // 日本
      'AU': 'Australia/Sydney'    // 澳洲
    };
  }
  
  generateMultiTimezoneSchedule(baseTime, targetTimezones) {
    const schedules = [];
    
    for (const [region, timezone] of Object.entries(targetTimezones)) {
      const localTime = this.convertToTimezone(baseTime, timezone);
      const cronExpression = this.timeToCron(localTime);
      
      schedules.push({
        region: region,
        timezone: timezone,
        localTime: localTime,
        cronExpression: cronExpression,
        utcTime: this.convertToUTC(localTime, timezone)
      });
    }
    
    return schedules;
  }
  
  convertToTimezone(baseTime, targetTimezone) {
    // 将基准时间转换到目标时区
    const date = new Date();
    date.setHours(baseTime.hour, baseTime.minute, 0, 0);
    
    return new Intl.DateTimeFormat('en-US', {
      timeZone: targetTimezone,
      hour: '2-digit',
      minute: '2-digit',
      hour12: false
    }).format(date);
  }
  
  timeToCron(timeString) {
    const [hour, minute] = timeString.split(':').map(Number);
    return `${minute} ${hour} * * *`;
  }
  
  convertToUTC(localTime, timezone) {
    const [hour, minute] = localTime.split(':').map(Number);
    const date = new Date();
    date.setHours(hour, minute, 0, 0);
    
    // 这里简化处理,实际应用中需要考虑DST等因素
    const utcTime = new Intl.DateTimeFormat('en-US', {
      timeZone: 'UTC',
      hour: '2-digit',
      minute: '2-digit',
      hour12: false
    }).format(date);
    
    return utcTime;
  }
  
  getBusinessHoursSchedule(region) {
    const businessHours = {
      'CN': { start: 9, end: 18 },   // 9:00-18:00
      'US': { start: 9, end: 17 },   // 9:00-17:00
      'EU': { start: 8, end: 17 },   // 8:00-17:00
      'JP': { start: 9, end: 18 },   // 9:00-18:00
      'AU': { start: 9, end: 17 }    // 9:00-17:00
    };
    
    const hours = businessHours[region];
    if (!hours) {
      throw new Error(`Unsupported region: ${region}`);
    }
    
    return {
      region: region,
      timezone: this.businessTimezones[region],
      businessHours: hours,
      cronExpressions: {
        start: `0 ${hours.start} * * 1-5`,  // 工作日开始
        end: `0 ${hours.end} * * 1-5`,      // 工作日结束
        lunch: `0 12 * * 1-5`,              // 午休时间
        hourly: `0 ${hours.start}-${hours.end} * * 1-5`  // 工作时间内每小时
      }
    };
  }
}

// 使用时区管理器
const timezoneManager = new TimezoneManager();

// 生成全球多时区的每日报表时间表
const reportTime = { hour: 9, minute: 0 }; // 各地区当地时间上午9点
const globalSchedule = timezoneManager.generateMultiTimezoneSchedule(
  reportTime,
  timezoneManager.businessTimezones
);

// 生成各地区的业务时间安排
const businessSchedules = Object.keys(timezoneManager.businessTimezones).map(region => 
  timezoneManager.getBusinessHoursSchedule(region)
);

console.log('全球定时任务调度配置完成');

return [{
  json: {
    globalReportSchedule: globalSchedule,
    businessHoursSchedules: businessSchedules,
    configuredAt: new Date().toISOString()
  }
}];

🎯 实战案例:复杂业务定时系统

电商平台定时任务系统

// Function 节点:电商定时任务管理系统
class ECommerceScheduleManager {
  constructor() {
    this.scheduleConfig = {
      // 日常运营任务
      daily: {
        'inventory-sync': {
          cron: '0 2 * * *',  // 每天凌晨2点
          description: '库存同步',
          priority: 'high',
          estimatedDuration: 1800000 // 30分钟
        },
        'sales-report': {
          cron: '0 8 * * *',  // 每天上午8点
          description: '日销售报表',
          priority: 'medium',
          estimatedDuration: 600000  // 10分钟
        },
        'price-monitoring': {
          cron: '0 */4 * * *', // 每4小时
          description: '价格监控',
          priority: 'medium',
          estimatedDuration: 300000  // 5分钟
        }
      },
      
      // 周期性任务
      weekly: {
        'customer-segmentation': {
          cron: '0 3 * * 1',  // 每周一凌晨3点
          description: '客户分群分析',
          priority: 'medium',
          estimatedDuration: 3600000 // 1小时
        },
        'inventory-forecast': {
          cron: '0 4 * * 1',  // 每周一凌晨4点
          description: '库存预测',
          priority: 'high',
          estimatedDuration: 1800000 // 30分钟
        }
      },
      
      // 月度任务
      monthly: {
        'financial-reconciliation': {
          cron: '0 1 1 * *',  // 每月1号凌晨1点
          description: '财务对账',
          priority: 'critical',
          estimatedDuration: 7200000 // 2小时
        },
        'performance-analysis': {
          cron: '0 2 1 * *',  // 每月1号凌晨2点
          description: '月度性能分析',
          priority: 'high',
          estimatedDuration: 1800000 // 30分钟
        }
      },
      
      // 特殊事件任务
      special: {
        'flash-sale-prep': {
          description: '闪购活动准备',
          priority: 'critical',
          estimatedDuration: 600000, // 10分钟
          triggerBefore: 3600000     // 活动前1小时执行
        },
        'promotion-cleanup': {
          description: '促销活动清理',
          priority: 'high',
          estimatedDuration: 1800000, // 30分钟
          triggerAfter: 1800000       // 活动后30分钟执行
        }
      }
    };
  }
  
  generateScheduleCalendar(year, month) {
    const calendar = [];
    const daysInMonth = new Date(year, month, 0).getDate();
    
    for (let day = 1; day <= daysInMonth; day++) {
      const date = new Date(year, month - 1, day);
      const dayTasks = this.getTasksForDate(date);
      
      calendar.push({
        date: date.toISOString().split('T')[0],
        dayOfWeek: date.getDay(),
        tasks: dayTasks,
        totalEstimatedDuration: dayTasks.reduce((sum, task) => sum + task.estimatedDuration, 0),
        riskLevel: this.calculateRiskLevel(dayTasks)
      });
    }
    
    return calendar;
  }
  
  getTasksForDate(date) {
    const tasks = [];
    const dayOfWeek = date.getDay();
    const dayOfMonth = date.getDate();
    const hour = date.getHours();
    
    // 检查日常任务
    Object.entries(this.scheduleConfig.daily).forEach(([taskId, config]) => {
      if (this.cronMatches(config.cron, date)) {
        tasks.push({
          id: taskId,
          type: 'daily',
          ...config,
          scheduledTime: this.parseCronTime(config.cron)
        });
      }
    });
    
    // 检查周度任务
    Object.entries(this.scheduleConfig.weekly).forEach(([taskId, config]) => {
      if (this.cronMatches(config.cron, date)) {
        tasks.push({
          id: taskId,
          type: 'weekly',
          ...config,
          scheduledTime: this.parseCronTime(config.cron)
        });
      }
    });
    
    // 检查月度任务
    Object.entries(this.scheduleConfig.monthly).forEach(([taskId, config]) => {
      if (this.cronMatches(config.cron, date)) {
        tasks.push({
          id: taskId,
          type: 'monthly',
          ...config,
          scheduledTime: this.parseCronTime(config.cron)
        });
      }
    });
    
    // 检查特殊事件
    const specialEvents = this.getSpecialEventsForDate(date);
    tasks.push(...specialEvents);
    
    return tasks.sort((a, b) => {
      const timeA = a.scheduledTime || '00:00';
      const timeB = b.scheduledTime || '00:00';
      return timeA.localeCompare(timeB);
    });
  }
  
  cronMatches(cronExpression, date) {
    // 简化的 cron 匹配实现
    const [minute, hour, day, month, weekday] = cronExpression.split(' ');
    
    const checkField = (field, value) => {
      if (field === '*') return true;
      if (field.includes('/')) {
        const [, interval] = field.split('/');
        return value % parseInt(interval) === 0;
      }
      if (field.includes('-')) {
        const [start, end] = field.split('-').map(Number);
        return value >= start && value <= end;
      }
      return parseInt(field) === value;
    };
    
    return checkField(minute, date.getMinutes()) &&
           checkField(hour, date.getHours()) &&
           checkField(day, date.getDate()) &&
           checkField(month, date.getMonth() + 1) &&
           checkField(weekday, date.getDay());
  }
  
  parseCronTime(cronExpression) {
    const [minute, hour] = cronExpression.split(' ');
    const h = hour === '*' ? 0 : parseInt(hour);
    const m = minute === '*' ? 0 : parseInt(minute);
    return `${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}`;
  }
  
  getSpecialEventsForDate(date) {
    const events = [];
    
    // 检查是否是促销日
    if (this.isPromotionDay(date)) {
      events.push({
        id: 'flash-sale-prep',
        type: 'special',
        ...this.scheduleConfig.special['flash-sale-prep'],
        scheduledTime: '10:00', // 促销开始前
        eventDate: date.toISOString()
      });
      
      events.push({
        id: 'promotion-cleanup',
        type: 'special',
        ...this.scheduleConfig.special['promotion-cleanup'],
        scheduledTime: '23:30', // 促销结束后
        eventDate: date.toISOString()
      });
    }
    
    return events;
  }
  
  isPromotionDay(date) {
    // 检查特殊促销日期
    const promotionDates = [
      { month: 11, day: 11 }, // 双11
      { month: 6, day: 18 },  // 618
      { month: 12, day: 12 }  // 双12
    ];
    
    return promotionDates.some(promo => 
      date.getMonth() + 1 === promo.month && date.getDate() === promo.day
    );
  }
  
  calculateRiskLevel(tasks) {
    let risk = 0;
    const totalDuration = tasks.reduce((sum, task) => sum + task.estimatedDuration, 0);
    const criticalTasks = tasks.filter(task => task.priority === 'critical').length;
    const highTasks = tasks.filter(task => task.priority === 'high').length;
    
    // 基于执行时间的风险
    if (totalDuration > 14400000) risk += 3; // 超过4小时
    else if (totalDuration > 7200000) risk += 2; // 超过2小时
    else if (totalDuration > 3600000) risk += 1; // 超过1小时
    
    // 基于任务优先级的风险
    risk += criticalTasks * 2;
    risk += highTasks * 1;
    
    // 基于任务数量的风险
    if (tasks.length > 10) risk += 2;
    else if (tasks.length > 5) risk += 1;
    
    if (risk >= 8) return 'high';
    if (risk >= 4) return 'medium';
    return 'low';
  }
  
  optimizeSchedule(calendar) {
    const optimizations = [];
    
    calendar.forEach(day => {
      // 检查高风险日期
      if (day.riskLevel === 'high') {
        optimizations.push({
          date: day.date,
          type: 'high_risk_day',
          message: `${day.date} 任务负载过重,建议调整部分非关键任务到其他时间`,
          suggestions: this.generateOptimizationSuggestions(day.tasks)
        });
      }
      
      // 检查时间冲突
      const conflicts = this.detectTimeConflicts(day.tasks);
      if (conflicts.length > 0) {
        optimizations.push({
          date: day.date,
          type: 'time_conflict',
          message: `检测到时间冲突,可能影响任务执行`,
          conflicts: conflicts
        });
      }
    });
    
    return optimizations;
  }
  
  generateOptimizationSuggestions(tasks) {
    const suggestions = [];
    
    // 建议移动低优先级任务
    const lowPriorityTasks = tasks.filter(task => task.priority === 'low' || task.priority === 'medium');
    if (lowPriorityTasks.length > 0) {
      suggestions.push({
        action: 'reschedule',
        tasks: lowPriorityTasks.map(t => t.id),
        reason: '将低优先级任务移至其他时间'
      });
    }
    
    // 建议分批执行
    const largeTasks = tasks.filter(task => task.estimatedDuration > 1800000); // 30分钟以上
    if (largeTasks.length > 2) {
      suggestions.push({
        action: 'split_execution',
        tasks: largeTasks.map(t => t.id),
        reason: '将大型任务分批执行以降低系统负载'
      });
    }
    
    return suggestions;
  }
  
  detectTimeConflicts(tasks) {
    const conflicts = [];
    
    for (let i = 0; i < tasks.length; i++) {
      for (let j = i + 1; j < tasks.length; j++) {
        const task1 = tasks[i];
        const task2 = tasks[j];
        
        if (task1.scheduledTime === task2.scheduledTime) {
          conflicts.push({
            time: task1.scheduledTime,
            conflictingTasks: [task1.id, task2.id],
            severity: this.getConflictSeverity(task1, task2)
          });
        }
      }
    }
    
    return conflicts;
  }
  
  getConflictSeverity(task1, task2) {
    const priorities = { 'critical': 4, 'high': 3, 'medium': 2, 'low': 1 };
    const maxPriority = Math.max(priorities[task1.priority], priorities[task2.priority]);
    
    if (maxPriority >= 4) return 'critical';
    if (maxPriority >= 3) return 'high';
    return 'medium';
  }
}

// 使用电商定时任务管理器
const scheduleManager = new ECommerceScheduleManager();

// 生成当前月份的任务日历
const now = new Date();
const calendar = scheduleManager.generateScheduleCalendar(now.getFullYear(), now.getMonth() + 1);

// 优化建议
const optimizations = scheduleManager.optimizeSchedule(calendar);

console.log(`生成 ${calendar.length} 天的任务调度计划,发现 ${optimizations.length} 个优化建议`);

return [{
  json: {
    calendar: calendar,
    optimizations: optimizations,
    summary: {
      totalDays: calendar.length,
      highRiskDays: calendar.filter(day => day.riskLevel === 'high').length,
      mediumRiskDays: calendar.filter(day => day.riskLevel === 'medium').length,
      optimizationCount: optimizations.length
    }
  }
}];

🚀 下一步学习

掌握定时任务和 Cron 后,继续学习:

  1. 监控告警 - 监控定时任务执行状态
  2. 性能优化 - 优化定时任务性能
  3. 运维维护 - 定时任务的长期维护

精确的时间控制是自动化的核心能力。通过掌握各种定时机制,你能构建出可靠、高效的定时任务系统,让工作流在正确的时间执行正确的操作!