Bencher Runner Protocol


Das runner-Binary und der API-Server kommunizieren über eine einzige WebSocket-Verbindung. Diese Referenz beschreibt dieses Protokoll: die ausgetauschten Nachrichten, den Job-Lebenszyklus, den sie antreiben, und wie Timeouts und Wiederverbindung verhindern, dass Jobs hängen bleiben. Sie ist die ausführliche Ergänzung zum Leitfaden Self-Hosted Runners.

Sie müssen nichts davon wissen, um einen Runner mit runner up zu betreiben; es wird zur Transparenz und für alle bereitgestellt, die Tooling rund um die API entwickeln.


Verbindung

Ein Runner unterhält für seinen gesamten Lebenszyklus eine einzige WebSocket-Verbindung zum API-Server. Dieselbe Verbindung bearbeitet sowohl die Job-Zuweisung als auch die Job-Ausführung, und sie bleibt über viele Jobs hinweg offen, wodurch ein erneuter Verbindungsaufbau und Handshake für jeden einzelnen vermieden wird.

  • Endpunkt: /v0/runners/{runner}/channel
  • Authentifizierung: Der Runner-Schlüssel wird beim Aufbau der Verbindung als Authorization: Bearer bencher_runner_<key>-Header gesendet.
  • Nachrichtengröße: Jede Nachricht ist durch das Limit request_body_max_bytes des Servers begrenzt (angewendet sowohl auf die maximale Nachrichten- als auch Frame-Größe). Eine Nachricht, die dieses Limit überschreitet, etwa ein completed-Payload, das große stdout-, stderr- oder Ausgabedateien transportiert, wird auf der Ebene des WebSocket-Protokolls abgelehnt.

Jede Nachricht ist ein JSON-Objekt mit einem event-Feld, das ihren Typ angibt.


Runner-Nachrichten

Nachrichten, die vom Runner an den Server gesendet werden.

Event Beschreibung Payload
ready Der Runner ist im Leerlauf und fordert einen Job an Optionales poll_timeout (1-900s) und runner-Metadaten (os, arch, version, optionaler Update-channel und optionale Binary-checksum)
running Job-Setup ist abgeschlossen und der Benchmark startet Keine
heartbeat Periodisches Lebenszeichen (etwa einmal pro Sekunde) Keine
completed Der Benchmark wurde erfolgreich abgeschlossen job (Job-UUID) und results (Ausgabe pro Iteration)
failed Der Benchmark ist fehlgeschlagen job (Job-UUID), results und error
canceled Bestätigt eine Abbruchanforderung vom Server job (Job-UUID)

Server-Nachrichten

Nachrichten, die vom Server an den Runner gesendet werden.

Event Beschreibung Payload
ack Bestätigt eine empfangene Nachricht Optionales job (Job-UUID)
job Weist dem Runner einen beanspruchten Job zu Der beanspruchte Job: seine Spec, Job-Konfiguration und ein kurzlebiges OCI-Pull-Token
no_job Das Poll-Timeout ist abgelaufen, ohne dass ein Job verfügbar war Keine
cancel Der Job wurde abgebrochen oder ist abgelaufen; Ausführung stoppen Keine
update Der Runner sollte sich selbst auf eine neue Version aktualisieren version, url (Download-URL) und checksum (SHA-256)

Das OCI-Pull-Token in einer job-Nachricht wird beim Beanspruchen des Jobs generiert und niemals gespeichert. Es ist auf das einzelne Projekt beschränkt, zu dem der Job gehört, ist nur zum Herunterladen (Pull) gedacht und ist kurzlebig, sodass ein kompromittierter Runner nur Images für das Projekt des von ihm beanspruchten Jobs herunterladen kann.

Auf dem stable-Update-Kanal wird ein update gesendet, wenn die Runner-Version von der Server-Version abweicht. Auf dem canary-Update-Kanal ist version gleich canary, und ein update wird gesendet, wenn die vom Runner selbst gemeldete Prüfsumme des Binaries vom veröffentlichten rollierenden Canary-Build abweicht.


Verbindungsablauf

Nach dem Verbinden tritt der Runner in eine Polling-Schleife im Leerlauf ein und sendet ready, bis der Server einen job zuweist (oder no_job zurückgibt, wenn das Poll-Timeout abläuft, oder update, wenn eine neue Version verfügbar ist). Sobald er einen Job hat, sendet der Runner running, streamt heartbeat-Nachrichten, während der Benchmark ausgeführt wird, und schließt mit einer terminalen completed- oder failed-Nachricht ab. Der Server bestätigt jede Nachricht mit ack, und die Verbindung bleibt offen, sodass der Runner für den nächsten Job in die Leerlaufschleife zurückkehrt.

Wird ein Job abgebrochen, antwortet der Server auf ein heartbeat mit cancel. Der Runner stoppt den Benchmark und antwortet mit canceled, was der Server bestätigt.

API ServerRunnerAPI ServerRunneralt[Job available][Poll timeout][Update available]loop[Idle / polling]loop[Benchmark executes]Connect with runner keyConnectedready (os, arch, version)job (Spec, config, OCI token)no_jobupdate (version, url, checksum)runningackheartbeatack (or cancel)completed (job, results)ack

Job-Lebenszyklus

Jeder Job durchläuft eine feste Menge von Zuständen, während er beansprucht, ausgeführt und verarbeitet wird.

Von Nach Auslöser
pending claimed Ein Runner beansprucht den Job
pending canceled Ein Benutzer bricht den Job ab
claimed running Der Runner sendet running
claimed failed Der Runner sendet failed, oder der Heartbeat läuft ab
claimed canceled Ein Benutzer bricht den Job ab
running completed Der Runner sendet completed
running failed Der Runner sendet failed, oder der Heartbeat läuft ab
running canceled Ein Benutzer bricht den Job ab, oder das harte Job-Timeout wird überschritten
completed processed Der Server verarbeitet die Ergebnisse erfolgreich
failed completed Der Runner sendet completed erneut und überschreibt einen Fehlschlag durch Heartbeat-Timeout

processed und canceled sind terminal. completed und failed sind quasi-terminal: completed geht in processed über, sobald die Ergebnisse geparst sind, und failed geht in completed über, wenn der Runner completed erneut sendet. Jeder Übergang verwendet einen Statusfilter bei seinem Datenbank-Update, sodass ein Job, der gleichzeitig geändert wurde, neu eingelesen statt überschrieben wird.

runner claims

user cancels

running

failed / timeout

user cancels

completed

failed / timeout

cancel / hard timeout

results recovered

results parsed

pending

claimed

canceled

running

failed

completed

processed


Timeouts & Wiederherstellung

Drei sich ergänzende Mechanismen stellen sicher, dass ein Job niemals hängen bleibt, selbst wenn ein Runner abstürzt oder seine Verbindung verliert.

Heartbeat-Timeout

Während die Verbindung offen ist, erkennt ein Read-Timeout einen Runner, der verbunden, aber stumm ist. Nur gültige Protokollnachrichten setzen den Timer zurück; ungültiges JSON, Ping/Pong-Frames und Binärnachrichten tun dies nicht. Bei einem Timeout wird ein Job, der länger als sein Timeout plus eine Karenzzeit gelaufen ist, als canceled markiert, andernfalls als failed (der Kontakt zum Runner ging verloren).

Hartes Job-Timeout

Der Server erzwingt unabhängig vom Verhalten des Runner eine harte maximale Ausführungsdauer, sodass ein fehlerhafter oder kompromittierter Runner nicht durch das Senden von Heartbeats unbegrenzt laufen kann. Wird das Limit (das Job-Timeout plus eine Karenzzeit) überschritten, wird der Job als canceled markiert und der Runner erhält eine cancel-Nachricht.

Wiederherstellung bei Verbindungsabbruch

Bricht die Verbindung ab, während ein Job noch in Bearbeitung ist, plant der Server nach dem Heartbeat-Timeout eine Prüfung ein. Hat sich der Runner erneut verbunden und die Heartbeats wieder aufgenommen, läuft der Job weiter; andernfalls wird der Job als failed markiert, oder als canceled, falls er das harte Timeout überschritten hatte. Beim Start stellt der Server außerdem verwaiste claimed-Jobs wieder her, plant Timeouts für in Bearbeitung befindliche Jobs neu und verarbeitet completed-Jobs erneut, deren Ergebnisse gespeichert, aber noch nicht geparst wurden.

Wiederverbindung & Ergebniszustellung

Wiederverbindung wird unterstützt und ist idempotent. Das erneute Senden von running für einen bereits laufenden Job aktualisiert nur dessen Lebenszeichen, und das erneute Senden einer terminalen completed-, failed- oder canceled-Nachricht ist immer sicher. Terminale Nachrichten tragen die Job-UUID und erhalten ein ack; bricht die Verbindung ab, bevor das ack eintrifft, speichert der Runner das Ergebnis und sendet es bei der nächsten Verbindung erneut, bevor er in den Leerlauf geht. Das tatsächliche completed-Ergebnis eines Runner kann sogar einen failed-Status durch Heartbeat-Timeout überschreiben.

Kein automatischer erneuter Versuch

Ein failed-Job wird nicht automatisch wiederholt. Ein fehlgeschlagener Benchmark ist ein Signal, kein zu verbergender Fehler, sodass das erneute Ausführen Ihnen überlassen bleibt.


Job-Ausgabe

Wenn ein Runner completed oder failed sendet, wird die vollständige Ausgabe im selben OCI-Storage-Backend gespeichert, das auch für Container-Images verwendet wird, unter dem Pfad {project}/output/v0/jobs/{job}.

Die gespeicherte Ausgabe enthält ein results-Array pro Iteration und, im Fehlerfall, einen error-String. Jede Iteration zeichnet ihren exit_code, stdout, stderr und eine Zuordnung aller erfassten Ausgabedateien zu ihren Inhalten auf. Nachdem die Ausgabe gespeichert ist, führt der Server den Benchmark-Harness-Adapter auf den Ergebnissen aus, um Metrics und Alerts in den Report zu parsen, wodurch der Job in processed übergeht.

Die Ausgabe wird zurückgegeben, wenn ein Job mit der GET /v0/projects/{project}/jobs/{job}-API abgefragt wird. Dasselbe request_body_max_bytes-Limit, das WebSocket-Nachrichten begrenzt, deckelt die Größe der Ausgabe, die ein Runner zustellen kann.



Published: Fri, June 19, 2026 at 8:00:00 AM UTC | Last Updated: Tue, July 7, 2026 at 8:00:00 AM UTC