Skip to content

JSON support for remote persistent workers #28405

@jayconrod

Description

@jayconrod

Description of the bug:

Bazel allows rule authors to change how messages to/from persistent workers are encoded by setting the requires-worker-protocol execution property to either json or proto. Using json allows a worker to avoid depending on the protobuf runtime, which can be quite large. This works great for local actions, but it this setting doesn't seem to be communicated to a remote execution service, so a service may try to run worker actions with proto, even if the worker only supports json. Only persistentWorkerKey is communicated via the Platform proto.

Could we standardize a new platform property name (perhaps simply requires-worker-protocol), then send that to the remote server if an action has it set?

Which category does this issue belong to?

Remote Execution

What's the simplest, easiest way to reproduce this bug? Please provide a minimal example if possible.

Here's a minimal Python worker that communicates in json. bazel build :scratch succeeds locally but fails remotely with EngFlow.

-- BUILD --
load("@rules_python//python:defs.bzl", "py_binary")
load(":def.bzl", "work")

work(
    name = "scratch",
    out = "scratch.txt",
    value = "1",
)

py_binary(
    name = "worker",
    srcs = ["worker.py"],
)
-- def.bzl --
def _work_impl(ctx):
    flags_file = ctx.actions.declare_file(ctx.label.name + ".args")
    args = ["/bin/bash", "-c", "echo '{}' >'{}'".format(ctx.attr.value, ctx.outputs.out.path)]
    ctx.actions.write(flags_file, "\n".join(args))
    ctx.actions.run(
        mnemonic = "Work",
        inputs = [flags_file],
        outputs = [ctx.outputs.out],
        arguments = ["@{}".format(flags_file.path)],
        executable = ctx.executable._worker,
        execution_requirements = {
            "supports-workers": "1",
            "requires-worker-protocol": "json",
        },
    )

work = rule(
    implementation = _work_impl,
    attrs = {
        "value": attr.string(mandatory = True),
        "out": attr.output(mandatory = True),
        "_worker": attr.label(
            default = ":worker",
            executable = True,
            cfg = "exec",
        ),
    },
)
-- worker.py --
#!/usr/bin/env python

import argparse
import json
import os
import os.path
import subprocess
import sys

def main():
    parser = argparse.ArgumentParser(
        prog = "run_api_worker",
        description = "Persistnet worker for running commands within a repo",
    )
    parser.add_argument("--persistent_worker", action='store_true')
    args = parser.parse_args()
    if not args.persistent_worker:
        sys.stderr.write("--persistent_worker is mandatory")
        sys.exit(1)
    
    for line in sys.stdin:
        line = line.strip()
        if not line:
            continue
        request = json.loads(line)
        response = serve_request(request)
        json.dump(response, sys.stdout)
        sys.stdout.write('\n')
        sys.stdout.flush()

def serve_request(request):
    wd = os.getcwd()
    if "sandbox_dir" in request:
        wd = os.path.join(wd, request["sandbox_dir"])
    try:
        proc = subprocess.run(
            request["arguments"],
            cwd = wd,
            stdout = subprocess.PIPE,
            stderr = subprocess.STDOUT)
        return {
            "exit_code": proc.returncode,
            "output": proc.stdout.decode("utf-8"),
        }
    except Exception as e:
        return {
            "exit_code": -1,
            "output": str(e),
        }

if __name__ == "__main__":
    main()

Which operating system are you running Bazel on?

macOS

What is the output of bazel info release?

release 10.0.0-pre.20260114.1

If bazel info release returns development version or (@non-git), tell us how you built Bazel.

No response

What's the output of git remote get-url origin; git rev-parse HEAD ?


If this is a regression, please try to identify the Bazel commit where the bug was introduced with bazelisk --bisect.

No response

Have you found anything relevant by searching the web?

No response

Any other information, logs, or outputs that you want to share?

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions