2026 Kleine Teams, geteilter Remote-Mac: Nomad-artige leichte Warteschlange vs. Cron-Fächerung
Szenario-Grenzen
Cron-Fächerung passt, wenn (a) ein klar benanntes Dienstkonto alle crontab-Einträge besitzt, (b) Jobs kurz und idempotent sind, (c) jede Zeile genau eine kritische Sektion mit flock und hartem timeout umschließt, und (d) Sie Minuten-Jitter bei der ersten Ausführung akzeptieren. Die Grenze ist erreicht, sobald mehrere Squads Jobs einreihen, CI und Menschen dieselbe „Lane“ beanspruchen oder Priorität (Release vor Nightly) und Fairness (kein verhungertes Team) nötig werden.
Nomad-artiges Scheduling — ob HashiCorp Nomad oder ein anderes System mit denselben Konzepten — lohnt sich, wenn max. Parallelität pro Constraint aus einem Ort lesbar sein soll („nur ein Codesign-Lane pro Host“, „zwei SwiftPM-Resolves, aber ein Archiv“) und Restart, Reschedule und Überlappungsverbote deklarativ statt per kopiertem Bash bleiben sollen. Auf macOS liegt der Control-Plane oft neben dem Mac (kleine Linux-VM); der Mac ist Ausführungs-Endpunkt per SSH, Runner-API oder Remote-Exec — das ist normal und trotzdem klarer als zwölf verstreute Cron-Zeilen.
Sobald zwei Jobs ohne dokumentierte Sperr-Domain dieselbe mutable Verzeichnisbaum beschreiben können, sind Sie in Queue- plus Lock-Territorium, nicht in „nur Cron“. Für Mehrknoten, wenn die zweite Maschine dazukommt und Deploy-Schritte mit der Queue synchron bleiben sollen, siehe OpenClaw MeshMac: einheitliches Deploy, Task-Queue und Sync. Soziale Fehler (Doppelbelegung, Geister-Sessions) fasst die FAQ: Warteschlange, Quota und Konflikte am geteilten Mac zusammen — Scheduler ersetzen diese Absprachen nicht.
Warteschlangenmodell: Vergleichstabelle
Spalten als Ops-Verträge: was Ihr On-Call um 02:00 Uhr ohne zwölf crontab-Dateien ableiten kann.
| Dimension | Cron-Fächerung + Wrapper | Nomad-artige leichte Queue |
|---|---|---|
| Latenz bis erster Lauf | Gebunden an Cron-Periode (oft 60 s); kürzere Intervalle erhöhen Herd-Risiko. | Ereignis- oder queue-getriebener Pickup; p50 oft unter einer Minute bei warmen Workern. |
| Parallelitäts-Kontrolle | Manuell: flock, Zähler, Redis — driftet leicht. |
Deklarativ: Task-Groups, count, Spread, Affinität — Caps an einer Stelle. |
| Präemption / Isolation | Keine, außer Sie bauen Signale selbst; „langen Job killen“ bleibt Folklore. | Policies für Restart, Reschedule, Prioritätsklassen; Audit-Log pro Allokation. |
| Zustand & Observability | Zerstreute Logs; Korrelations-IDs selten konsistent. | Zentrale Job-Historie; Standard-Labels (job, alloc) für Metriken. |
| Ops-Aufwand | Geringe Installationskosten, hohe Drift-Kosten beim Teamwachstum. | Höher upfront; weniger Überraschung beim fünften Engineer. |
| Typischer Fehlmodus | Stille Überlappung + Cache-Korruption. | Falsch modellierte Constraints (Spread) → Starvation — fixbar im Job-Spec, nicht im Chat. |
Ausführbare Konfigurationsskizzen
Cron (gestrafft): eine Lane, explizite Sperre, kein unkontrolliertes Aufstapeln.
# Fragment /etc/crontab — nur Benutzer buildlane
*/1 * * * * buildlane /usr/bin/flock -n /var/run/meshmac/build.lane.lock \
timeout 45m /usr/local/bin/run-ci-dequeue.sh >>/var/log/meshmac/dequeue.log 2>&1
Jedes Dequeue-Skript sollte zu Beginn eine max. Pending-Tiefe prüfen: überschreitet die Redis-Liste oder SQLite-Queue Länge 20, mit Exit 77 abbrechen und pagern — Clients dürfen nicht endlos hängen. Shell-flock-Rezepte: Build-Warteschlange & flock FAQ.
Nomad-artiger periodischer Batch (illustratives HCL auf der Control-Plane; reale Mac-Arbeit im Skript per SSH/Runner):
job "meshmac-mac-build" {
datacenters = ["dc1"]
type = "batch"
periodic {
cron = "*/2 * * * *"
prohibit_overlap = true
}
group "lane" {
count = 1
task "dequeue" {
driver = "exec"
config {
command = "/usr/local/bin/run-ci-dequeue.sh"
}
resources {
cpu = 500
memory = 512
}
restart {
attempts = 3
interval = "30m"
delay = "30s"
mode = "delay"
}
}
}
}
prohibit_overlap = true für periodische Jobs, die einer physischen Archiv-Lane entsprechen — Scheduler-Äquivalent zu „nie zwei vollständige Xcode-Archive auf derselben DerivedData-Wurzel“. Die eigentliche Mac-Arbeit bleibt in run-ci-dequeue.sh, die Policy im Job-Spec.
Berechtigungen und Sperren
Scheduler schedulen; macOS erzwingt. Nutzen Sie ein dediziertes Konto buildlane (oder pro Team), getrennt von interaktiven Konsolen-Usern; Keychain-Zugriff nur für die Signing-Identitäten dieses Kontos. Root-LaunchDaemons sollten sudo -u buildlane aufrufen — nicht Xcode als root.
- Sperr-Granularität: je gemeinsame Ressource eine
.lock(Pods, npm-Cache, Simulator-Slot), nicht eine globale Festplatten-Sperre, außer Sie wollen alles serialisieren. - Queue-Metadaten:
job_id,commit,runner_nameals kleine JSON-Sidecar neben der Lock-Datei — On-Call sieht, wer noch laufen sollte. - Präemption & Aufräumen: beim Kill einer Allokation
trap-Handler für partielle.xcarchive-Reste und Lock-Freigabe; der Scheduler wiederholt Versuche — die SSD nicht mit Waisen füllen.
Build-Konflikt: Akzeptanz-Checkliste
- ☐ Zwei parallele Dry-Runs auf demselben Checkout-Pfad erzeugen keine unkontrollierten Schreib-Überlappungen (oder Überlappung nur in einem
flock-Block unter ca. 120 s). - ☐ CI und manuelle Skripte nutzen denselben Dequeue-Einstieg — kein „geheimer“ Cron, der die Queue umgeht.
- ☐ Median der Lock-Wartezeit unterhalb Ihrer publizierten SLA; Alarm, wenn p95 > 15 min.
- ☐ Kill des laufenden Jobs hinterlässt keinen Zombie-
flock-Halter (PID prüfen, Lock-Recovery dokumentiert). - ☐ Nach fünf aufeinanderfolgenden Nightly-Archiven bleibt freier Speicher > 15 % — sonst Lanes erweitern oder Knoten hinzufügen.
Timeout- und Backoff-Parameter
Werte ins interne Runbook übernehmen und an gemessene p95-Buildzeiten anpassen.
| Parameter | Cron + Shell-Baseline | Nomad-artige Baseline |
|---|---|---|
| Wall-Clock pro Job | timeout 45m leichte Lane; 90m schweres Archiv. |
Task-kill_timeout auf dieselben Zahlen; Defaults ~30 s sind für Xcode fatal. |
| Lock-Wartezeit | flock -w 180 für Paketmanager; bei Timeout fail-fast mit Metrik. |
Warte-Logik im Worker; Scheduler-Restart nicht spin-tight — mindestens delay = "30s". |
| Retry-Backoff | Exponentiell: 30 s, 60 s, 120 s Deckel; Jitter Faktor 0,8–1,2. |
reschedule mit max_delay = "5m", delay_function = "exponential". |
| Globales Pending-Cap | z. B. 20 wartende Jobs pro Lane; ablehnen mit verständlichem HTTP-Status/Exit-Code. | Am Submitter und in der Queue erzwingen — Nomad kennt Ihre Business-SLA nicht. |
Bash-5+-Beispiel für Jitter vor Dequeue-Retry: sleep $((30 + RANDOM % 30)). Pro Branch attempt, next_backoff_s, reason loggen — Grafana/CloudWatch-Abfragen bleiben langweilig.
FAQ
- Muss Nomad auf dem Mac selbst laufen?
- Nein. Viele Teams betreiben den Scheduler unter Linux und behandeln jeden Mac als Remote-Executor. Entscheidend ist ein deklarativer Vertrag für Überlappung, Restart und Historie — nicht die Marke der Binärdatei.
- Cron ist „einfacher“ — warum explodiert meine Queue trotzdem?
- Einfachheit bei der Installation bedeutet nicht Einfachheit im Betrieb. Fächerung ohne zentrale Tiefen-Limits erzeugt versteckte Backlogs; kürzere Cron-Intervalle treiben nur mehr Prozesse in dieselben Sperren.
- Wo leben Präemptions-Regeln?
- In der Scheduler-Schicht für Allokations-Lebenszyklus, in Runbooks für menschliche Sessions (VNC-Pairing). Nicht auf „mittags archiviert keiner“ verlassen.
Knoten hinzufügen, bevor die Konkurrenz eskalieren muss
Cron-Fächerung bleibt ein legitimer Single-Lane-Hack, wenn Sperren, Timeouts und Tiefen-Limits wie Produktionscode gepflegt werden. Nomad-artige Schedules zahlen sich aus, wenn Parallelitäts-Schlüssel, Restart-Policy und Audit-Historie zur Realität Ihres geteilten Xcode-Zeitfensters passen — macOS-Berechtigungen und flock-Domains sind in beiden Fällen Pflicht. Hält ein Host Ihre Checkliste nicht mehr ein, skalieren Sie mit Mehrknoten oder dedizierten Build-Ressourcen statt riskanter Parallelität auf einer SSD.
Auf der Startseite finden Sie Überblick zu Remote-Mac-Angeboten; im Hilfezentrum SSH, VNC und Onboarding ohne Login-Hürden; unter Preise vergleichen Sie Pakete für zusätzliche Knoten oder geteilte Builder-Kapazität. Im Blog ergänzen z. B. GHA Runner, Routing & Queue-Matrix und Pool-FAQ mit Warteschlange & Quota.