Persistent Workers
Persistent workers keep compatible compiler and tool processes alive across
remote actions. This reduces repeated tool startup cost for JVM-heavy tools such
as javac, scalac, and kotlinc, and for worker wrappers around tools such
as tsc.
The repository examples live in
deployment-examples/persistent-workers.
NativeLink uses Bazel execution requirements to choose the persistent worker path:
execution_requirements = { "supports-workers": "1", "requires-worker-protocol": "proto", # or "json"}If requires-worker-protocol is omitted, NativeLink treats the action as
proto.
def _javac_worker_impl(ctx): args = ctx.actions.args() args.add("@%s" % ctx.outputs.argfile.path)
ctx.actions.run( executable = ctx.executable.javac_worker, arguments = [args], inputs = ctx.files.srcs + [ctx.outputs.argfile], outputs = [ctx.outputs.jar], mnemonic = "Javac", execution_requirements = { "supports-workers": "1", "requires-worker-protocol": "proto", }, )def _tsc_worker_impl(ctx): args = ctx.actions.args() args.add("@%s" % ctx.outputs.tsconfig.path)
ctx.actions.run( executable = ctx.executable.tsc_worker, arguments = [args], inputs = ctx.files.srcs + [ctx.outputs.tsconfig], outputs = ctx.outputs.js, mnemonic = "TypeScriptCompile", execution_requirements = { "supports-workers": "1", "requires-worker-protocol": "json", }, )def _kotlinc_worker_impl(ctx): args = ctx.actions.args() args.add("@%s" % ctx.outputs.argfile.path)
ctx.actions.run( executable = ctx.executable.kotlinc_worker, arguments = [args], inputs = ctx.files.srcs + [ctx.outputs.argfile], outputs = [ctx.outputs.jar], mnemonic = "KotlinCompile", execution_requirements = { "supports-workers": "1", "requires-worker-protocol": "proto", }, )NativeLink derives a WorkerKey from:
- the executable path
- startup arguments before the first
@argfile requires-worker-protocol
Actions with the same key can reuse the same warm process. NativeLink starts the
tool with --persistent_worker, sends one WorkRequest per action, and reads one
WorkResponse per action.
The implementation includes an integration test that sends two remote actions to
one JSON worker. The first action writes 1, and the second writes 2, proving
that the second action reused the already-running worker process.
Run the focused test gates with:
bazel test \ //nativelink-worker:unit_test \ //nativelink-worker:integration \ //nativelink-scheduler:integration \ --test_output=errors