Bencher Protocole Runner


Le binaire runner et le serveur API communiquent via une unique connexion WebSocket. Cette référence décrit ce protocole : les messages échangés, le cycle de vie du Job qu’ils pilotent, et comment les délais d’attente et la reconnexion empêchent les Jobs de rester bloqués. C’est le complément détaillé du guide Runners auto-hébergés.

Vous n’avez pas besoin de connaître tout cela pour exploiter un Runner avec runner up ; ceci est fourni à des fins de transparence et pour quiconque construit des outils autour de l’API.


Connexion

Un Runner maintient une unique connexion WebSocket vers le serveur API pendant tout son cycle de vie. La même connexion gère à la fois l’assignation et l’exécution des Jobs, et elle reste ouverte d’un Job à l’autre, évitant une reconnexion et un handshake pour chacun.

  • Point de terminaison : /v0/runners/{runner}/channel
  • Authentification : la clé du Runner est envoyée sous forme d’en-tête Authorization: Bearer bencher_runner_<key> lors de l’établissement de la connexion.
  • Taille des messages : chaque message est borné par la limite request_body_max_bytes du serveur (appliquée à la fois à la taille maximale du message et de la trame). Un message qui dépasse cette limite, tel qu’une charge utile completed transportant un volume important de stdout, stderr ou de fichiers de sortie, est rejeté au niveau du protocole WebSocket.

Chaque message est un objet JSON avec un champ event qui identifie son type.


Messages du Runner

Messages envoyés du Runner vers le serveur.

Event Description Charge utile
ready Le Runner est inactif et demande un Job poll_timeout optionnel (1-900 s) et métadonnées runner (os, arch, version, channel de mise à jour optionnel et checksum du binaire optionnel)
running La préparation du Job est terminée et le benchmark démarre Aucune
heartbeat Signal de vie périodique (environ une fois par seconde) Aucune
completed Le benchmark s’est terminé avec succès job (UUID du Job) et results (sortie par itération)
failed Le benchmark a échoué job (UUID du Job), results et error
canceled Accuse réception d’une annulation depuis le serveur job (UUID du Job)

Messages du serveur

Messages envoyés du serveur vers le Runner.

Event Description Charge utile
ack Accuse réception d’un message reçu job optionnel (UUID du Job)
job Assigne un Job réclamé au Runner Le Job réclamé : son Spec, la configuration du Job, et un jeton de récupération OCI à courte durée de vie
no_job Le délai d’attente du poll a expiré sans Job disponible Aucune
cancel Le Job a été annulé ou a expiré ; arrêter l’exécution Aucune
update Le Runner doit se mettre à jour vers une nouvelle version version, url (URL de téléchargement) et checksum (SHA-256)

Le jeton de récupération OCI dans un message job est généré lorsque le Job est réclamé et n’est jamais stocké. Il est limité au seul projet auquel le Job appartient, est en lecture seule (pull only), et a une courte durée de vie, de sorte qu’un Runner compromis ne peut récupérer que les Images du projet du Job qu’il a réclamé.

Sur le canal de mise à jour stable, un update est envoyé lorsque la version du Runner diffère de la version du serveur. Sur le canal de mise à jour canary, version vaut canary et un update est envoyé lorsque le checksum du binaire rapporté par le Runner lui-même diffère du build canary continu publié.


Flux de connexion

Après s’être connecté, le Runner entre dans une boucle d’interrogation inactive, envoyant ready jusqu’à ce que le serveur assigne un job (ou renvoie no_job lorsque le poll expire, ou update lorsqu’une nouvelle version est disponible). Une fois qu’il dispose d’un Job, le Runner envoie running, diffuse des messages heartbeat pendant l’exécution du benchmark, et termine par un message terminal completed ou failed. Le serveur accuse réception de chaque message avec ack, et la connexion reste ouverte afin que le Runner retourne à la boucle inactive pour le Job suivant.

Si un Job est annulé, le serveur répond à un heartbeat avec cancel. Le Runner arrête le benchmark et répond avec canceled, ce dont le serveur accuse réception.

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

Cycle de vie du Job

Chaque Job traverse un ensemble fixe d’états au fur et à mesure qu’il est réclamé, exécuté et traité.

De Vers Déclencheur
pending claimed Un Runner réclame le Job
pending canceled Un utilisateur annule le Job
claimed running Le Runner envoie running
claimed failed Le Runner envoie failed
claimed unknown Le serveur perd le contact avec le Runner
claimed canceled Un utilisateur annule le Job
running completed Le Runner envoie completed
running failed Le Runner envoie failed
running unknown Le serveur perd le contact avec le Runner
running canceled Un utilisateur annule le Job, ou le délai d’attente strict du Job est dépassé
unknown completed Le Runner envoie completed
unknown failed Le Runner envoie failed
unknown canceled Un utilisateur annule le Job, ou le délai d’attente strict du Job est dépassé
completed processed Le serveur traite les résultats avec succès
completed failed Le serveur ne parvient pas à traiter les résultats
completed unknown Au démarrage, le serveur constate que les résultats stockés ont été perdus

processed, failed et canceled sont terminaux : un Job failed ou canceled ne change plus jamais d’état. completed est quasi terminal : completed passe à processed une fois les résultats analysés, à failed s’ils ne peuvent pas être traités, ou à unknown si le serveur constate au démarrage qu’ils ont été perdus. unknown signifie que le serveur a perdu le contact avec le Runner et ne connaît pas encore le résultat. Il est résolu lorsque le Runner se manifeste à nouveau, avec le résultat qu’il envoie, ou en canceled lorsque l’échéance du Job est passée. Chaque transition utilise un filtre de statut sur sa mise à jour en base de données, de sorte qu’un Job modifié de façon concurrente est relu plutôt qu’écrasé.

runner claims

user cancels

running

failed

lost contact

user cancels

completed

failed

lost contact

cancel / hard timeout

completed

failed

cancel / hard timeout

results parsed

processing failed

results lost

pending

claimed

canceled

running

failed

unknown

completed

processed


Délais d’attente & récupération

Trois mécanismes complémentaires garantissent qu’un Job ne reste jamais bloqué, même si un Runner plante ou perd sa connexion.

Délai d’attente du heartbeat

Tant que la connexion est ouverte, un délai d’attente de lecture détecte un Runner connecté mais silencieux. Seuls les messages de protocole valides réinitialisent le minuteur ; le JSON invalide, les trames ping/pong et les messages binaires ne le font pas. À l’expiration, un Job qui s’est exécuté plus longtemps que son délai d’attente plus un délai de grâce est marqué canceled, et sinon marqué unknown (le contact avec le Runner a été perdu).

Délai d’attente strict du Job

Le serveur impose une durée d’exécution maximale stricte, indépendante du comportement du Runner, de sorte qu’un Runner bogué ou compromis ne puisse pas s’exécuter indéfiniment en envoyant des heartbeats. Lorsque la limite (le délai d’attente du Job plus un délai de grâce) est dépassée, le Job est marqué canceled et le Runner reçoit un message cancel. La limite court à partir du démarrage du Job, ou de sa réclamation s’il n’a jamais démarré, et s’applique aussi à un Job unknown.

Récupération après déconnexion

Si la connexion tombe alors qu’un Job est encore en cours, le serveur planifie une vérification après le délai d’attente du heartbeat. Si le Runner s’est reconnecté et a repris ses heartbeats, le Job continue ; sinon, le Job est marqué unknown, ou canceled s’il avait dépassé le délai d’attente strict. Le serveur vérifie à nouveau un Job unknown à son échéance. Au démarrage, le serveur marque également les Jobs claimed orphelins comme unknown, replanifie les délais d’attente des Jobs en cours et unknown, et retraite les Jobs completed dont les résultats ont été stockés mais pas encore analysés ; un Job completed dont les résultats ont été perdus est marqué unknown afin que le Runner puisse les renvoyer.

Reconnexion & livraison des résultats

La reconnexion est prise en charge et idempotente. Renvoyer running pour un Job déjà en cours ne fait que rafraîchir sa vivacité, et renvoyer un message terminal completed, failed ou canceled est toujours sûr. Les messages terminaux transportent l’UUID du Job et reçoivent un ack ; si la connexion tombe avant l’arrivée de l’ack, le Runner stocke le résultat et le renvoie lors de la prochaine connexion avant de redevenir inactif. Le résultat d’un Runner résout un Job unknown. Un Job failed ou canceled ne change plus jamais d’état : un résultat tardif est acquitté, pour que le Runner cesse de le renvoyer, puis ignoré.

Aucune nouvelle tentative automatique

Un Job failed n’est pas réessayé automatiquement. Un benchmark en échec est un signal, pas une erreur à cacher, sa réexécution vous est donc laissée.


Sortie du Job

Lorsqu’un Runner envoie completed ou failed, la sortie complète est stockée dans le même backend de stockage OCI utilisé pour les Images de conteneur, au chemin {project}/output/v0/jobs/{job}.

La sortie stockée contient un tableau results par itération et, en cas d’échec, une chaîne error. Chaque itération enregistre son exit_code, son stdout, son stderr, ainsi qu’une carte de tous les fichiers de sortie collectés avec leur contenu. Une fois la sortie stockée, le serveur exécute l’adaptateur du harnais de benchmark sur les résultats pour analyser les Metrics et les Alerts dans le Report, faisant passer le Job à processed.

La sortie est renvoyée lorsqu’un Job est interrogé avec l’API GET /v0/projects/{project}/jobs/{job}. La même limite request_body_max_bytes qui borne les messages WebSocket plafonne la taille de la sortie qu’un Runner peut livrer.



Published: Fri, June 19, 2026 at 8:00:00 AM UTC | Last Updated: Wed, September 23, 2026 at 12:00:00 AM UTC