Esta página descreve os workers multiplex, como escrever regras compatíveis com multiplex e soluções alternativas para determinadas limitações.
Os workers multiplex permitem que o Bazel processe várias solicitações com um único processo de worker. Para workers de várias linhas de execução, o Bazel usa menos recursos para atingir o mesmo ou melhor desempenho. Por exemplo, em vez de ter um processo de worker por worker, o Bazel pode ter quatro workers multiplexados se comunicando com o mesmo processo de worker, que pode processar solicitações em paralelo. Para linguagens como Java e Scala, isso economiza tempo de aquecimento do JVM e tempo de compilação do JIT e, em geral, permite usar um cache compartilhado entre todos os workers do mesmo tipo.
Visão geral
Há duas camadas entre o servidor do Bazel e o processo do trabalhador. Para algumas mnemônicas que podem executar processos em paralelo, o Bazel recebe um WorkerProxy
do pool de workers. O WorkerProxy
encaminha solicitações para o processo do worker
sequencialmente com um request_id
, o processo do worker processa a solicitação
e envia respostas ao WorkerMultiplexer
. Quando o WorkerMultiplexer
recebe uma resposta, ele analisa o request_id
e encaminha as respostas
de volta para o WorkerProxy
correto. Assim como ocorre com workers não multiplexados, toda a comunicação é feita sobre a entrada/saída padrão, mas a ferramenta não pode usar apenas stderr
para saída visível ao usuário (veja abaixo).
Cada worker tem uma chave. O Bazel usa o código hash da chave (composto por variáveis de ambiente, raiz raiz e mnemônica) para determinar qual WorkerMultiplexer
usar. Os WorkerProxy
s se comunicam com o mesmo WorkerMultiplexer
se tiverem o mesmo código. Portanto, presumindo que as variáveis de ambiente e a raiz de execução sejam as mesmas em uma única invocação do Bazel, cada mnemônico único pode ter apenas um processo de WorkerMultiplexer
e um de trabalho. O número total de workers, incluindo workers regulares e WorkerProxy
s, ainda é limitado por --worker_max_instances
.
Como escrever regras compatíveis com multiplex
O processo de trabalho da regra precisa ser de várias linhas de execução para aproveitar os workers multiplex. O Protobuf permite que um conjunto de regras analise uma única solicitação, mesmo que haja várias solicitações se acumulando no stream. Sempre que o
processo do worker analisa uma solicitação do stream, ele precisa processá-la em
uma nova linha de execução. Como uma linha de execução diferente pode ser concluída e gravar no stream ao mesmo tempo, o processo do worker precisa garantir que as respostas sejam gravadas atomicamente (as mensagens não se sobrepõem). As respostas precisam conter o request_id
da solicitação que estão processando.
Como processar a saída multiplex
Os workers multiplex precisam ser mais cuidadosos do que com os workers complexos. Qualquer item enviado para stderr
vai para um único arquivo de registro compartilhado entre todos os WorkerProxy
s do mesmo tipo, intercalados aleatoriamente entre solicitações simultâneas. Embora o redirecionamento de stdout
para stderr
seja uma boa ideia, não colete essa saída no campo output
de WorkResponse
, porque isso pode mostrar ao usuário partes incorretas da saída.
Se a ferramenta enviar apenas saídas orientadas ao usuário para stdout
ou stderr
, será necessário alterar esse comportamento antes de ativar workers de multiplex.
Como ativar workers multiplex
Os workers multiplex não são ativados por padrão. Um conjunto de regras pode ativar workers multiplex
usando a tag supports-multiplex-workers
no
execution_requirements
de uma ação (assim como a tag supports-workers
permite workers regulares). Como é o caso ao usar workers regulares, é necessário especificar uma estratégia de worker, seja no nível do conjunto de regras (por exemplo, --strategy=[some_mnemonic]=worker
) ou geralmente no nível da estratégia (por exemplo, --dynamic_local_strategy=worker,standalone
). Nenhuma sinalização adicional é necessária e supports-multiplex-workers
tem precedência sobre supports-workers
, se ambas forem definidas. É possível desativar workers multiplex globalmente transmitindo --noworker_multiplex
.
É recomendável que um conjunto de regras use workers multiplex, se possível, para reduzir a pressão da memória e melhorar o desempenho. No entanto, os workers multiplex não são compatíveis com a execução dinâmica, a menos que implementem o sandbox multiplex. A tentativa de executar trabalhos multiplex fora do sandbox com execução dinâmica usará silenciosamente workers únicos no sandbox.
Sandbox de multiplex
Os workers multiplex podem ser colocados no sandbox adicionando compatibilidade explícita a eles nas implementações do worker. Embora o sandbox de worker de singleplex possa ser feito executando cada processo de worker no próprio sandbox, os workers multiplex compartilham o diretório de trabalho do processo entre várias solicitações paralelas. Para permitir o sandbox de workers multiplex, ele precisa oferecer suporte à leitura e gravação em um subdiretório especificado em cada solicitação, em vez de diretamente no diretório de trabalho.
Para oferecer suporte ao sandbox de multiplex, o worker precisa usar o campo sandbox_dir
do WorkRequest
e usá-lo como prefixo para todas as leituras e gravações de arquivo.
Embora os campos arguments
e inputs
permaneçam inalterados de uma solicitação sem sandbox, as entradas reais são relativas a sandbox_dir
. O worker precisa converter caminhos de arquivo encontrados em arguments
e inputs
para ler esse caminho modificado, além de gravar todas as saídas relativas a sandbox_dir
.
Isso inclui caminhos como '.', bem como caminhos encontrados em arquivos especificados nos argumentos (como argumentos "argfile").
Quando um worker é compatível com o sandbox multiplex, o conjunto de regras poderá declarar essa
compatibilidade adicionando supports-multiplex-sandboxing
ao
execution_requirements
de uma ação. O Bazel usará o sandbox multiplex se a sinalização --experimental_worker_multiplex_sandboxing
for transmitida ou se o worker for usado com a execução dinâmica.
Os arquivos de trabalho de um worker multiplex no sandbox ainda são relativos ao diretório de trabalho do processo do worker. Assim, se um arquivo for usado para executar o worker e como uma entrada, ele precisará ser especificado como uma entrada no argumento flagfile, bem como em tools
, executable
ou runfiles
.