EMZETT.
Login

Cron Job (Vercel)

Kurz: Eine Route, die Vercel automatisch zu festen Zeiten selbst aufruft (statt dass ein Browser oder User sie besucht) — für wiederkehrende Hintergrundaufgaben, die niemand manuell anstoßen muss.

Genauer: In Vercel wird ein Cron-Job in vercel.json deklariert (Pfad + Zeitplan im Cron-Format, z. B. täglich um eine bestimmte Uhrzeit). Vercel schickt dann selbst einen Request an diese Route — der Code dahinter ist eine ganz normale API-Route, technisch nicht anders als eine, die ein Mensch aufruft.

Kontext bei uns: Bei Emzett nutzt /api/ticket-reminder das für automatische Erinnerungsmails, wenn Admin-Nachrichten in Support-Tickets 12+ Stunden unbeantwortet bleiben — läuft täglich, ganz ohne dass Michael selbst daran denken muss.

Im Detail

Deklaration und Cron-Syntax

Die Deklaration in vercel.json folgt Standard-Cron-Syntax (Minute, Stunde, Tag, Monat, Wochentag):

{
  "crons": [
    { "path": "/api/ticket-reminder", "schedule": "0 12 * * *" },
    { "path": "/api/cart-cleanup", "schedule": "0 9 * * *" }
  ]
}

"0 12 * * *" bedeutet: jeden Tag um 12:00 Uhr UTC. Die fünf Felder (von links nach rechts: Minute 0-59, Stunde 0-23, Tag des Monats 1-31, Monat 1-12, Wochentag 0-6) lassen sich mit * (jeder Wert), Listen (1,15), Bereichen (1-5) und Schrittweiten (*/15 für alle 15 Minuten) kombinieren — dieselbe Syntax wie beim klassischen Unix-Cron-Daemon, den Vercels Implementierung bewusst nachbildet, damit bestehendes Cron-Wissen direkt übertragbar ist.

Authentifizierung der Cron-Aufrufe

Ein wichtiger Sicherheitsaspekt: Da die Cron-Route technisch eine ganz normale, öffentlich erreichbare API-Route ist, könnte grundsätzlich auch jeder andere sie manuell aufrufen — Vercel setzt deshalb bei echten Cron-Aufrufen einen speziellen Authorization-Header (Bearer <CRON_SECRET>), den die Route serverseitig prüfen sollte, um zu verhindern, dass Dritte dieselbe Route beliebig oft manuell triggern (z. B. um mehrfach Erinnerungsmails zu verschicken oder Rechenzeit/Kosten zu verursachen):

export async function GET(request: Request) {
  const authHeader = request.headers.get("authorization");
  if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) {
    return new Response("Unauthorized", { status: 401 });
  }
  // eigentliche Cron-Logik
}

CRON_SECRET wird dabei als normale Environment Variable gesetzt und von Vercel automatisch bei jedem tatsächlichen Cron-Aufruf mitgeschickt.

Timeouts und Ausführungslimits

Cron-Routen unterliegen denselben Function-Timeout-Limits wie andere Serverless/Edge Functions der Plattform — eine Aufgabe, die länger als das konfigurierte Limit braucht (z. B. das Versenden sehr vieler E-Mails in einer Schleife), wird zwangsweise abgebrochen. Für längere Batch-Aufgaben ist es deshalb üblich, die Cron-Route nur als “Trigger” zu verwenden, der eine asynchrone Hintergrundaufgabe anstößt (z. B. über eine Queue), statt die gesamte Arbeit synchron innerhalb des Cron-Requests selbst zu erledigen.

Limits nach Tarif

Auf dem kostenlosen Hobby-Tarif ist die Ausführungshäufigkeit von Cron-Jobs limitiert (z. B. maximal einmal täglich pro Job) — für häufigere Intervalle (minütlich, stündlich) ist ein bezahlter Tarif nötig. Zusätzlich begrenzen die meisten Tarife auch die maximale Anzahl gleichzeitig konfigurierter Cron-Jobs pro Projekt, was bei Projekten mit vielen wiederkehrenden Hintergrundaufgaben relevant werden kann.

Siehe auch: Vercel, Environment Variables