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.

EventDescriptionCharge utile
readyLe Runner est inactif et demande un Jobpoll_timeout optionnel (1-900 s) et métadonnées runner (os, arch, version)
runningLa préparation du Job est terminée et le benchmark démarreAucune
heartbeatSignal de vie périodique (environ une fois par seconde)Aucune
completedLe benchmark s’est terminé avec succèsjob (UUID du Job) et results (sortie par itération)
failedLe benchmark a échouéjob (UUID du Job), results et error
canceledAccuse réception d’une annulation depuis le serveurjob (UUID du Job)

Messages du serveur

Messages envoyés du serveur vers le Runner.

EventDescriptionCharge utile
ackAccuse réception d’un message reçujob optionnel (UUID du Job)
jobAssigne un Job réclamé au RunnerLe Job réclamé : son Spec, la configuration du Job, et un jeton de récupération OCI à courte durée de vie
no_jobLe délai d’attente du poll a expiré sans Job disponibleAucune
cancelLe Job a été annulé ou a expiré ; arrêter l’exécutionAucune
updateLe Runner doit se mettre à jour vers une nouvelle versionversion, 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é.


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

DeVersDéclencheur
pendingclaimedUn Runner réclame le Job
pendingcanceledUn utilisateur annule le Job
claimedrunningLe Runner envoie running
claimedfailedLe Runner envoie failed, ou le heartbeat expire
claimedcanceledUn utilisateur annule le Job
runningcompletedLe Runner envoie completed
runningfailedLe Runner envoie failed, ou le heartbeat expire
runningcanceledUn utilisateur annule le Job, ou le délai d’attente strict du Job est dépassé
completedprocessedLe serveur traite les résultats avec succès
failedcompletedLe 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