定时任务与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 后,继续学习:
精确的时间控制是自动化的核心能力。通过掌握各种定时机制,你能构建出可靠、高效的定时任务系统,让工作流在正确的时间执行正确的操作!