Zum Inhalt springen
use-cases / cron-per-customer / hero
Multi-Tenant SaaS / Per-Customer-Scheduling

Eine eigene Crontab für jeden Kunden, automatisch

Dein SaaS lässt jeden Kunden seine eigene Report-Generierung schedulen. Das naive Design ist ein gemeinsamer Scheduler, Kunden-IDs im Job-Payload, Daumen drücken, dass niemand andere aushungert. Das Hoody-Design gibt jedem Tenant seinen eigenen Container und seinen eigenen hoody-cron-Service.

Doku lesen

Three lifecycle states, one HTTP API. PROVISION adds entries, cron ticks run them, DELETE suspends. Each tenant's cron lives in its own container — no shared queue, no noisy-neighbor risk.

use-cases / cron-per-customer / mechanism

Drei API-Aufrufe treiben den kompletten Tenant-Lebenszyklus an

Jeder Customer-Container exposed die hoody-cron-HTTP-API. Provisioning mit POST, Überprüfung mit GET, Suspend mit DELETE. Keine geteilte Queue, keine Priority-Lane, keine Scheduler-Config zum Redeploy.

POST einen Managed Entry — erstellt einen Cron-Job mit UUID, Enabled-State und Feld schedule_humanPOST /provisioning
request
# POST managed entry for acme-corp tenant
POST acme-cron.hoody.com/users/root/entries
Content-Type: application/json

{
  "schedule": "0 9 * * *",
  "command": "/usr/local/bin/digest.sh",
  "comment": "daily digest",
  "enabled": true
}
response
HTTP/1.1 201 Created
Content-Type: application/json

{
  "id": "7d3f2a1b-8c4e-4f9a-b2d5",
  "schedule": "0 9 * * *",
  "schedule_human": "At 09:00",
  "enabled": true,
  "user": "root"
}
201 Created. Entry-ID wird für zukünftige PATCH oder DELETE zurückgegeben. schedule_human bestätigt, dass der Ausdruck geparst wurde.

Jeder Tab zeigt den exakten API-Aufruf, den deine Control-Plane macht. Die Managed-Entries-API nutzt UUIDs, um einzelne Jobs ohne komplette Crontab-Replacement anzusprechen. Pro-User-Isolation bedeutet, dass nichts über acme-corps Schedule für globex-saas sichtbar ist.

use-cases / cron-per-customer / powers

Was das Abrechnungsmodell deutlich macht

Ein Pauschal-Server. Sechzig Tenant-Container. Die Mathematik ist brutal einfach.

Fleet-Abrechnungs-BreakdownPro-Tenant-Kosten = Server geteilt durch Tenants
Deine Tenants
acme-corpSM
globex-saasMD
initech-incLG
+ 57 weitere
Pauschal-Server / Monat$29Ein Bare-Metal-Knoten. 60 Container. Rechnung bleibt flach.
÷Tenants
Pro-Tenant-Kosten<$0,49Sinkt wenn du mehr Tenants hinzufügst

Noisy-Neighbor-Incidents verschwinden

Wenn initech-incs scrape.js hängt, feuert acme-corps 9-Uhr-Digest trotzdem. Verschiedene Crontabs, verschiedene Process-Trees, verschiedene Filesystems.

Schedule-Änderungen propagieren sofort

POST einen neuen Entry und der hoody-cron-Service des Tenants nimmt ihn sofort auf. Kein zentraler Scheduler zum Reload, keine Broadcast nötig.

Pro-Tenant-Logs, ein Container

Wenn globex-saas fragt, warum ihr 18-Uhr-Rollup letzten Dienstag zweimal lief, liest du ein Container-Log — nicht einen geteilten Scheduler-Grep über neun Maschinen.

use-cases / cron-per-customer / compare

Geteilter Scheduler vs. Container-gebundene Crontab

Drei Achsen, an denen das alte Design dein Team Steuern kostet — und das Hoody-Design einfach nicht.

AchseGeteilter SchedulerContainer-gebunden
Isolation
tenant_id im Job-PayloadEine schlechte Zeile, jeder Tenant-Queue blockiert
Eigene /etc/crontab pro ContainerHänger sind lokal. Immer.
Provisioning
INSERT INTO scheduled_jobsMigrationskopplung, Schema-Lock
PUT /users/root/crontabEin HTTP-Call, atomares Replace
Audit
grep tenant_id=42 logs/*9 Maschinen, 1 Logfile pro Stück
GET ctr_8a3f1c/cron/logEin Container, ein Log, eine Wahrheit

Die alte Spalte ist, was jedes Team das erste Mal schreibt, wenn es Multi-Tenant-Scheduling shippt. Die neue Spalte ist, was du shippst, wenn die Plattform jedem Tenant standardmäßig einen eigenen Container gibt.

use-cases / cron-per-customer / capacity

Kapazität an den Rändern

Was eine einzelne Bare-Metal-Hoody-Box leistet, wenn jeder Kunde seine eigene Crontab bekommt.

  1. Tenants pro Box60

    Sechzig Customer-Container auf einem Bare-Metal-Knoten, jeder mit eigenem laufenden hoody-cron-Service. Kein gemeinsamer Scheduler als Bottleneck.

  2. Schedule-Propagation<1s

    Vom PUT-Request bis zum ersten Tick des neuen Schedules, beobachtet über eine Flotte von 60 Containern auf einem typischen 64-Core-Knoten.

  3. Cross-Tenant-Queues0

    Es gibt buchstäblich keine geteilte Queue, Priority-Lane oder Scheduler-Thread, um die zwei Tenants konkurrieren. Isolation ist das Substrat.

Kapazitätszahlen sind typische Werte, beobachtet auf einem 64-Core-/256GB-Bare-Metal-Knoten mit Standard-Hoody-Container-Dichte. Die tatsächliche Kapazität hängt von den Pro-Tenant-CPU- und Memory-Budgets sowie der Arbeit jedes Cron-Jobs ab. Die Null bei Cross-Tenant-Queues ist strukturell, kein Benchmark.

use-cases / cron-per-customer / punchline

Ein Cron eines Kunden kann den eines anderen nicht aushungern, weil sie nicht in derselben Crontab stehen.

Vorher / geteilter SchedulerNachher / Container-gebunden
Geteiltscheduled_jobs WHERE tenant_id = 42Eine Zeile in einer Tabelle, aus der alle lesen
Pro TenantPUT acme-cron.hoody.com/users/root/crontabEin HTTP-Call, ein Container, eine Crontab
Cron-API lesen
use-cases / cron-per-customer / replaces

Was das ersetzt

Die Architekturen, die Teams bauen, um eine Crontab über mehrere Tenants zu teilen. Hoody steckt jeden Tenant in seine eigene Crontab — kein Router, keine Fairness-Queue, kein Noisy Neighbour.

  • Geteilte Multi-Tenant-CrontabsEine schlechte Regex hungert 400 Kunden aus
  • Custom Tenant-IsolationEin Scheduler mit tenant_id auf jeder Zeile
  • Postgres pg_cronDatenbank-gebunden; ein Upgrade, alle gehen kaputt
  • Quartz-Scheduler mit FilternEine JVM und eine sharded Queue pro Region
  • Sidekiq Tenant-QueuesZwölf Queues, zwölf Config-Files
  • Kubernetes CronJobs pro TenantEin Namespace, eine RBAC-Rolle, ein YAML, ein Pager
use-cases / cron-per-customer / cta

Hör auf, tenant_id überall hinzuschreiben. Gib jedem Kunden seinen eigenen Container und lass Cron tun, was Cron schon immer getan hat — in Isolation.

Doku lesen
use-cases / cron-per-customer / related

Lies die anderen