Bencher Runner Protocol
O binário runner e o servidor de API se comunicam por uma única conexão
WebSocket. Esta referência descreve esse protocolo: as mensagens trocadas, o ciclo de vida do Job
que elas conduzem e como os timeouts e a reconexão evitam que os Jobs fiquem travados. É a
companhia detalhada do guia Self-Hosted Runners.
Você não precisa saber nada disso para operar um Runner com runner up;
isso é fornecido por transparência e para qualquer pessoa que esteja construindo ferramentas em torno da API.
Conexão
Um Runner mantém uma única conexão WebSocket ao servidor de API durante todo o seu ciclo de vida. A mesma conexão trata tanto a atribuição quanto a execução do Job, e permanece aberta entre muitos Jobs, evitando uma reconexão e handshake para cada um.
- Endpoint:
/v0/runners/{runner}/channel - Autenticação: a chave do Runner é enviada como um cabeçalho
Authorization: Bearer bencher_runner_<key>quando a conexão é estabelecida. - Tamanho da mensagem: cada mensagem é limitada pelo limite
request_body_max_bytesdo servidor (aplicado tanto ao tamanho máximo da mensagem quanto ao do frame). Uma mensagem que excede esse limite, como um payloadcompletedcarregando grandesstdout,stderrou arquivos de saída, é rejeitada no nível do protocolo WebSocket.
Toda mensagem é um objeto JSON com um campo event que identifica seu tipo.
Mensagens do Runner
Mensagens enviadas do Runner para o servidor.
| Event | Descrição | Payload |
|---|---|---|
ready | O Runner está ocioso e solicitando um Job | poll_timeout opcional (1-900s) e metadados do runner (os, arch, version) |
running | A configuração do Job está concluída e o benchmark está iniciando | Nenhum |
heartbeat | Sinal periódico de atividade (cerca de uma vez por segundo) | Nenhum |
completed | O benchmark foi concluído com sucesso | job (UUID do Job) e results (saída por iteração) |
failed | O benchmark falhou | job (UUID do Job), results e error |
canceled | Confirma um cancelamento vindo do servidor | job (UUID do Job) |
Mensagens do Servidor
Mensagens enviadas do servidor para o Runner.
| Event | Descrição | Payload |
|---|---|---|
ack | Confirma uma mensagem recebida | job opcional (UUID do Job) |
job | Atribui um Job reivindicado ao Runner | O Job reivindicado: sua Spec, a configuração do Job e um token de pull OCI de curta duração |
no_job | O timeout de polling expirou sem nenhum Job disponível | Nenhum |
cancel | O Job foi cancelado ou expirou; pare a execução | Nenhum |
update | O Runner deve se auto-atualizar para uma nova versão | version, url (URL de download) e checksum (SHA-256) |
O token de pull OCI em uma mensagem job é gerado quando o Job é reivindicado e nunca é armazenado.
Ele é restrito ao único projeto ao qual o Job pertence, é somente para pull e é de curta duração,
de modo que um Runner comprometido só pode baixar Images do projeto do Job que reivindicou.
Fluxo de Conexão
Após conectar, o Runner entra em um loop de polling ocioso,
enviando ready até que o servidor atribua um job
(ou retorne no_job quando o polling expira, ou update quando uma nova versão está disponível).
Assim que tem um Job, o Runner envia running,
transmite mensagens heartbeat enquanto o benchmark executa
e finaliza com uma mensagem terminal completed ou failed.
O servidor confirma cada mensagem com ack,
e a conexão permanece aberta para que o Runner retorne ao loop ocioso para o próximo Job.
Se um Job é cancelado, o servidor responde a um heartbeat com cancel.
O Runner para o benchmark e responde com canceled, que o servidor confirma.
Ciclo de Vida do Job
Cada Job passa por um conjunto fixo de estados conforme é reivindicado, executado e processado.
| De | Para | Gatilho |
|---|---|---|
| pending | claimed | Um Runner reivindica o Job |
| pending | canceled | Um usuário cancela o Job |
| claimed | running | O Runner envia running |
| claimed | failed | O Runner envia failed, ou o heartbeat expira |
| claimed | canceled | Um usuário cancela o Job |
| running | completed | O Runner envia completed |
| running | failed | O Runner envia failed, ou o heartbeat expira |
| running | canceled | Um usuário cancela o Job, ou o timeout rígido do Job é excedido |
| completed | processed | O servidor processa os resultados com sucesso |
| failed | completed | O Runner reenvia completed, sobrepondo uma falha por timeout de heartbeat |
processed e canceled são terminais.
completed e failed são quase-terminais:
completed transiciona para processed assim que os resultados são analisados,
e failed transiciona para completed se o Runner reenviar completed.
Toda transição usa um filtro de status em sua atualização no banco de dados,
de modo que um Job que foi modificado concorrentemente é relido em vez de sobrescrito.
Timeouts & Recuperação
Três mecanismos complementares garantem que um Job nunca fique travado, mesmo que um Runner falhe ou perca sua conexão.
Timeout de Heartbeat
Enquanto a conexão está aberta, um timeout de leitura detecta um Runner que está conectado mas silencioso.
Apenas mensagens de protocolo válidas reiniciam o temporizador;
JSON inválido, frames de ping/pong e mensagens binárias não.
Em caso de timeout, um Job que rodou por mais tempo do que seu timeout mais um período de carência é marcado como canceled,
e caso contrário marcado como failed (o contato com o Runner foi perdido).
Timeout Rígido do Job
O servidor impõe uma duração máxima de execução rígida, independente do comportamento do Runner,
de modo que um Runner com bug ou comprometido não possa rodar indefinidamente enviando heartbeats.
Quando o limite (o timeout do Job mais um período de carência) é excedido,
o Job é marcado como canceled e o Runner recebe uma mensagem cancel.
Recuperação de Desconexão
Se a conexão cai enquanto um Job ainda está em andamento,
o servidor agenda uma verificação após o timeout de heartbeat.
Se o Runner reconectou e retomou os heartbeats, o Job continua;
caso contrário, o Job é marcado como failed, ou canceled se tiver excedido o timeout rígido.
Na inicialização, o servidor também recupera Jobs claimed órfãos,
reagenda timeouts para Jobs em andamento
e reprocessa Jobs completed cujos resultados foram armazenados mas ainda não analisados.
Reconexão & Entrega de Resultados
A reconexão é suportada e idempotente.
Reenviar running para um Job já em execução apenas atualiza sua atividade,
e reenviar uma mensagem terminal completed, failed ou canceled é sempre seguro.
Mensagens terminais carregam o UUID do Job e recebem um ack;
se a conexão cair antes de o ack chegar,
o Runner armazena o resultado e o reenvia na próxima conexão antes de ficar ocioso.
O resultado completed real de um Runner pode até sobrepor um status failed por timeout de heartbeat.
Sem Retentativa Automática
Um Job failed não é retentado automaticamente.
Um benchmark que falhou é um sinal, não um erro a ser escondido,
então reexecutá-lo fica a seu critério.
Saída do Job
Quando um Runner envia completed ou failed,
a saída completa é armazenada no mesmo backend de armazenamento OCI usado para as Images de contêiner,
no caminho {project}/output/v0/jobs/{job}.
A saída armazenada contém um array results por iteração e, em caso de falha, uma string error.
Cada iteração registra seu exit_code, stdout, stderr
e um mapa de quaisquer arquivos de saída coletados para seus conteúdos.
Após a saída ser armazenada, o servidor executa o adaptador de harness de benchmark sobre os resultados
para analisar Metrics e Alerts no Report, transicionando o Job para processed.
A saída é retornada quando um Job é consultado com a API GET /v0/projects/{project}/jobs/{job}.
O mesmo limite request_body_max_bytes que limita as mensagens WebSocket
restringe o tamanho da saída que um Runner pode entregar.