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.

EventBeschreibungPayload
readyDer Runner ist im Leerlauf und fordert einen Job anOptionales poll_timeout (1-900s) und runner-Metadaten (os, arch, version)
runningJob-Setup ist abgeschlossen und der Benchmark startetKeine
heartbeatPeriodisches Lebenszeichen (etwa einmal pro Sekunde)Keine
completedDer Benchmark wurde erfolgreich abgeschlossenjob (Job-UUID) und results (Ausgabe pro Iteration)
failedDer Benchmark ist fehlgeschlagenjob (Job-UUID), results und error
canceledBestätigt eine Abbruchanforderung vom Serverjob (Job-UUID)

Server-Nachrichten

Nachrichten, die vom Server an den Runner gesendet werden.

EventBeschreibungPayload
ackBestätigt eine empfangene NachrichtOptionales job (Job-UUID)
jobWeist dem Runner einen beanspruchten Job zuDer beanspruchte Job: seine Spec, Job-Konfiguration und ein kurzlebiges OCI-Pull-Token
no_jobDas Poll-Timeout ist abgelaufen, ohne dass ein Job verfügbar warKeine
cancelDer Job wurde abgebrochen oder ist abgelaufen; Ausführung stoppenKeine
updateDer Runner sollte sich selbst auf eine neue Version aktualisierenversion, 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.


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.

VonNachAuslöser
pendingclaimedEin Runner beansprucht den Job
pendingcanceledEin Benutzer bricht den Job ab
claimedrunningDer Runner sendet running
claimedfailedDer Runner sendet failed, oder der Heartbeat läuft ab
claimedcanceledEin Benutzer bricht den Job ab
runningcompletedDer Runner sendet completed
runningfailedDer Runner sendet failed, oder der Heartbeat läuft ab
runningcanceledEin Benutzer bricht den Job ab, oder das harte Job-Timeout wird überschritten
completedprocessedDer Server verarbeitet die Ergebnisse erfolgreich
failedcompletedDer 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