Cron-Ausdrücke Best Practices: Von Fallstricken bis Produktion

Dienstprogramme

Cron-Ausdrücke: 5 Felder zur Zeitsteuerung

┌───────── Minute (0-59)
│ ┌───────── Stunde (0-23)
│ │ ┌───────── Tag (1-31)
│ │ │ ┌───────── Monat (1-12)
│ │ │ │ ┌───────── Wochentag (0-7, 0 und 7 sind Sonntag)
│ │ │ │ │
* * * * *

I. Syntax-Schnellreferenz

Ausdruck Bedeutung Ausführungshäufigkeit
* * * * * Jede Minute 1440 Mal/Tag
*/5 * * * * Alle 5 Minuten 288 Mal/Tag
0 * * * * Jede volle Stunde 24 Mal/Tag
0 9 * * * Täglich um 9:00 1 Mal/Tag
0 9 * * 1-5 Werktags um 9:00 5 Mal/Woche
30 2 1 * * Am 1. jedes Monats um 2:30 1 Mal/Monat
0 0 1 1 * Am 1. Januar um 0:00 1 Mal/Jahr

Sonderzeichen

Zeichen Bedeutung Beispiel
* Beliebiger Wert * * * * *
, Aufzählung 0 9,12,18 * * * (9/12/18 Uhr)
- Bereich 0 9-17 * * 1-5 (Werktags 9-17 Uhr)
/ Schrittweite */15 * * * * (alle 15 Minuten)
L Letzter 0 0 L * * (letzter Tag des Monats)
W Nächster Werktag 0 0 1W * * (nächster Werktag zum 1.)
# N-ter Wochentag 0 0 * * 5#3 (dritter Freitag)

II. Häufige Fallstricke

Fallstrick 1: Tag und Wochentag gleichzeitig angeben

# Falsches Verständnis: Am 15. jedes Monats UND an einem Freitag
0 0 15 * 5

# Tatsächliche Bedeutung: Am 15. jedes Monats ODER jeden Freitag (Vereinigung!)
# Korrekte Schreibweise erfordert zusätzliche Logik

Regel: Wenn Tag und Wochentag gleichzeitig angegeben werden, wird die Vereinigung genommen, nicht die Schnittmenge.

Fallstrick 2: Zeitzonenprobleme

# Erwartet: Ausführung um 9:00 Peking-Zeit
0 9 * * *

# Server in UTC-Zeitzone → tatsächliche Ausführung um 17:00 Peking-Zeit!
# Lösung: Zeitzone explizit angeben
// node-cron Zeitzone angeben
cron.schedule('0 9 * * *', task, {
  scheduled: true,
  timezone: 'Asia/Shanghai',
});

Fallstrick 3: 60-Sekunden-Schreibfehler

# Falsch: Das Minutenfeld hat keine 60
0 0 60 * * *

# Richtig: Jede Stunde ausführen
0 * * * *

Fallstrick 4: 30. Februar

# Februar hat keinen 30., dieser Ausdruck wird im Februar nicht ausgeführt
0 0 30 2 *

Fallstrick 5: Sommerzeit

Bei der Sommerzeitumstellung können bestimmte Zeiten nicht existieren oder doppelt vorkommen:

Frühling vorstellen: 2:00 → 3:00 (2:30 existiert nicht)
Herbst zurückstellen: 2:00 → 1:00 (1:30 wird zweimal ausgeführt)

Empfehlung: UTC-Zeitzone verwenden, um Sommerzeitprobleme zu vermeiden.


III. Cron-Ausdrücke mit ToolsKu verifizieren

Bedienungsschritte

  1. Öffnen Sie das Cron-Ausdruck-Tool
  2. Geben Sie den Cron-Ausdruck ein
  3. Lesen Sie die deutsche Interpretation:
    • 0 9 * * 1-5 → "Montag bis Freitag um 09:00"
    • */30 8-18 * * * → "Jeden Tag alle 30 Minuten von 08:00-18:00"
  4. Zeigen Sie die Liste der nächsten Ausführungen an (5-10 nächste)
  5. Überprüfen Sie, ob der Ausdruck gültig ist

IV. Produktionsreifes Design zeitgesteuerter Aufgaben

Nebenläufigkeitskontrolle

import { CronJob } from 'cron';

let isRunning = false;

const job = new CronJob('0 */5 * * * *', async () => {
  if (isRunning) {
    console.log('Vorherige Runde noch nicht abgeschlossen, diese Ausführung überspringen');
    return;
  }

  isRunning = true;
  try {
    await processData();
  } finally {
    isRunning = false;
  }
});

Verteilte Sperre (Multi-Instanz-Bereitstellung)

import { Redis } from 'ioredis';

const redis = new Redis();

async function acquireLock(key, ttl = 300) {
  const acquired = await redis.set(key, '1', 'EX', ttl, 'NX');
  return acquired === 'OK';
}

const job = new CronJob('0 2 * * *', async () => {
  const lockKey = `cron:daily-report:${new Date().toISOString().slice(0, 10)}`;

  if (!(await acquireLock(lockKey))) {
    console.log('Andere Instanz hat die Sperre bereits, überspringen');
    return;
  }

  try {
    await generateDailyReport();
  } finally {
    await redis.del(lockKey);
  }
});

Fehler-Wiederholung

async function runWithRetry(task, maxRetries = 3, delay = 5000) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await task();
    } catch (error) {
      console.error(`Versuch ${attempt} fehlgeschlagen:`, error.message);
      if (attempt < maxRetries) {
        await sleep(delay * attempt); // Inkrementelle Verzögerung
      } else {
        throw error;
      }
    }
  }
}

const job = new CronJob('0 */10 * * * *', () => {
  runWithRetry(syncData, 3, 5000);
});

Timeout-Kontrolle

async function runWithTimeout(task, timeoutMs = 60000) {
  return Promise.race([
    task(),
    new Promise((_, reject) =>
      setTimeout(() => reject(new Error('Aufgabe hat das Zeitlimit überschritten')), timeoutMs)
    ),
  ]);
}

V. Aufgabenüberwachung

Ausführungsprotokoll

const job = new CronJob('0 2 * * *', async () => {
  const startTime = Date.now();
  const context = { job: 'daily-sync', startedAt: new Date().toISOString() };

  try {
    await runWithRetry(syncData);
    context.status = 'success';
  } catch (error) {
    context.status = 'failed';
    context.error = error.message;
    await sendAlert(context); // Warnung
  } finally {
    context.duration = Date.now() - startTime;
    await logExecution(context); // Protokoll aufzeichnen
  }
});

Gesundheitsprüfung

// Letzte erfolgreiche Ausführungszeit speichern
await redis.set('cron:last-success:daily-sync', Date.now());

// Gesundheitsprüfung: Wenn seit über 25 Stunden nicht ausgeführt, Warnung auslösen
const lastSuccess = await redis.get('cron:last-success:daily-sync');
if (Date.now() - lastSuccess > 25 * 3600 * 1000) {
  await sendAlert({ type: 'cron_stale', job: 'daily-sync' });
}

VI. Häufige Muster zeitgesteuerter Aufgaben

Anforderung Cron-Ausdruck Beschreibung
Stündliche Datensynchronisation 0 * * * * Zur vollen Stunde
Werktags-Morgenbericht 0 9 * * 1-5 Montag bis Freitag um 9:00
Tägliche Sicherung 0 2 * * * Um 2:00 Uhr nachts
Wöchentliche Bereinigung 0 3 * * 0 Sonntags um 3:00
Monatlicher Abgleich 0 6 1 * * Am 1. jedes Monats um 6:00
Heartbeat alle 15 Minuten */15 * * * * Hochfrequenzprüfung
Quartalsbericht 0 8 1 1,4,7,10 * Erster Tag des Quartalsmonats

VII. Liste der Best Practices

  1. Immer UTC-Zeitzone verwenden, es sei denn, das Geschäft erfordert zwingend lokale Zeit
  2. Tag und Wochentag nicht gleichzeitig angeben, Vereinigungs-Falle vermeiden
  3. Nebenläufigkeitskontrolle: Nur eine Instanz führt zur gleichen Zeit aus
  4. Verteilte Sperre: Doppelte Ausführung bei Multi-Instanz-Bereitstellung verhindern
  5. Fehler-Wiederholung + Warnungen: Nicht stillschweigend fehlschlagen
  6. Timeout-Kontrolle: Verhindern, dass Aufgaben unbegrenzt hängen
  7. Idempotentes Design: Wiederholte Ausführung liefert gleiche Ergebnisse
  8. Ausführungsprotokoll: Zeit, Dauer und Status jeder Ausführung aufzeichnen
  9. Ausdrücke mit Tools verifizieren: Korrekte Semantik vor Bereitstellung bestätigen
#Cron#定时任务#crontab#时区#运维