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, ou le heartbeat expire
claimed canceled Un utilisateur annule le Job
running completed Le Runner envoie completed
running failed Le Runner envoie failed, ou le heartbeat expire
running 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
failed completed Le Runner renvoie completed, écrasant un échec dû à l’expiration du heartbeat

processed et canceled sont terminaux. completed et failed sont quasi terminaux : completed passe à processed une fois les résultats analysés, et failed passe à completed si le Runner renvoie completed. 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 / timeout

user cancels

completed

failed / timeout

cancel / hard timeout

results recovered

results parsed

pending

claimed

canceled

running

failed

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é failed (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.

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é failed, ou canceled s’il avait dépassé le délai d’attente strict. Au démarrage, le serveur récupère également les Jobs claimed orphelins, replanifie les délais d’attente des Jobs en cours, et retraite les Jobs completed dont les résultats ont été stockés mais pas encore analysés.

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 completed réel d’un Runner peut même écraser un statut failed dû à l’expiration du heartbeat.

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: Tue, July 7, 2026 at 8:00:00 AM UTC