영구 작업자를 사용하면 빌드 속도를 높일 수 있습니다. 빌드에서 시작 비용이 높거나 작업 간 캐싱의 이점을 누릴 수 있는 작업이 반복되는 경우 이러한 작업을 실행하기 위해 자체 영구 작업자를 구현하는 것이 좋습니다.
Bazel 서버는 stdin/stdout을 사용하여 작업자와 통신합니다. 프로토콜 버퍼 또는 JSON 문자열 사용을 지원합니다.
작업자 구현은 다음 두 부분으로 구성됩니다.
- 그 작업자.
- 작업자를 사용하는 규칙.
작업자 만들기
영구 작업자는 몇 가지 요구사항을 준수합니다.
- `
stdin`에서 WorkRequests 를 읽습니다. - `
stdout`에 WorkResponses (및WorkResponse만)를 씁니다. --persistent_worker플래그를 허용합니다. 래퍼는--persistent_worker명령줄 플래그를 인식해야 하며, 이 플래그가 전달된 경우에만 영구적으로 유지해야 합니다. 그렇지 않으면 일회성 컴파일을 실행하고 종료해야 합니다.
프로그램이 이러한 요구사항을 준수하는 경우 영구 작업자로 사용할 수 있습니다.
작업 요청
A WorkRequest에는 작업자 인수 목록, 작업자가 액세스할 수 있는 입력을 나타내는 경로-다이제스트 쌍 목록(적용되지는 않지만 이 정보를 캐싱에 사용할 수 있음), 요청 ID(단일 작업자의 경우 0)가 포함됩니다.
참고: 프로토콜 버퍼 사양은 "스네이크 케이스" (request_id)를 사용하지만 JSON 프로토콜은 "카멜 케이스" (requestId)를 사용합니다. 이 문서에서는 JSON 예시에서 카멜 케이스를 사용하지만 프로토콜과 관계없이 필드에 관해 설명할 때는 스네이크 케이스를 사용합니다.
{
"arguments" : ["--some_argument"],
"inputs" : [
{ "path": "/path/to/my/file/1", "digest": "fdk3e2ml23d"},
{ "path": "/path/to/my/file/2", "digest": "1fwqd4qdd" }
],
"requestId" : 12
}
선택적 verbosity 필드를 사용하여 작업자로부터 추가 디버깅 출력을 요청할 수 있습니다.
작업자로부터. 출력할 항목과 출력 방법은 전적으로 작업자에 달려 있습니다. 값이 클수록 자세한 출력을 나타냅니다. Bazel에 --worker_verbose 플래그를 전달하면 verbosity 필드가 10으로 설정되지만, 다양한 출력 양에 대해 더 작거나 큰 값을 수동으로 사용할 수 있습니다.
선택적 sandbox_dir 필드는
멀티플렉스 샌드박싱을 지원하는 작업자만 사용합니다.
작업 응답
WorkResponse에는 요청 ID, 0 또는 0이 아닌 종료 코드, 요청 처리 또는 실행 중에 발생한 오류를 설명하는
출력 메시지가 포함됩니다. 작업자는 호출하는 모든 도구의 stdout 및 stderr를 캡처하고 WorkResponse를 통해 보고해야 합니다. 작업자 프로세스의 stdout에 쓰는 것은 작업자 프로토콜을 방해하므로 안전하지 않습니다.
작업자 프로세스의 stderr에 쓰는 것은 안전하지만 결과는
개별 작업에 귀속되는 대신 작업자별 로그 파일에 수집됩니다.
{
"exitCode" : 1,
"output" : "Action failed with the following message:\nCould not find input
file \"/path/to/my/file/1\"",
"requestId" : 12
}
protobuf의 표준에 따라 모든 필드는 선택사항입니다. 하지만 Bazel은
WorkRequest와 상응하는 WorkResponse가 동일한 요청
ID를 갖도록 요구하므로 요청 ID가 0이 아닌 경우 지정해야 합니다. 유효한
WorkResponse입니다.
{
"requestId" : 12,
}
0은 이 요청을 다른 요청과 동시에 처리할 수 없는 경우 사용되는 "단일" 요청을 나타내는 request_id입니다. 서버는 지정된 작업자가
request_id 0만 포함된 요청 또는
request_id 0보다 큰 요청을 수신하도록 보장합니다. 단일 요청은 직렬로 전송됩니다. 예를 들어 서버가 응답을 수신할 때까지 다른 요청을 전송하지 않는 경우 (취소 요청 제외, 아래 참고)입니다.
참고
- 각 프로토콜 버퍼 앞에는
varint형식의 길이가 붙습니다 (MessageLite.writeDelimitedTo()참고). - JSON 요청 및 응답 앞에는 크기 표시기가 붙지 않습니다.
- JSON 요청은 protobuf와 동일한 구조를 유지하지만 표준 JSON을 사용하고 모든 필드 이름에 카멜 케이스를 사용합니다.
- protobuf와 동일한 이전 버전과의 호환성 및 이후 버전과의 호환성 속성을 유지하기 위해 JSON 작업자는 이러한 메시지의 알 수 없는 필드를 허용하고 누락된 값에 protobuf 기본값을 사용해야 합니다.
- Bazel은 요청을 protobuf로 저장하고 protobuf의 JSON 형식을 사용하여 JSON으로 변환합니다.
취소
작업자는 작업 요청이 완료되기 전에 취소되도록 선택적으로 허용할 수 있습니다.
이는 로컬
실행이 더 빠른 원격 실행에 의해 정기적으로 중단될 수 있는 동적 실행과 관련하여 특히 유용합니다. 취소를 허용하려면
supports-worker-cancellation: 1 필드에
execution-requirements을 추가하고 (아래 참고)
--experimental_worker_cancellation 플래그를 설정합니다.
취소 요청 은 WorkRequest의 cancel 필드가 설정된 것이며 (마찬가지로 취소 응답 은 WorkResponse의 was_cancelled
필드가 설정된 것입니다). 취소 요청 또는 취소
응답에 있어야 하는 유일한 다른 필드는 취소할 요청을 나타내는 request_id입니다. request_id
필드는 단일 작업자의 경우 0이거나 멀티플렉스 작업자의 경우 이전에
전송된 WorkRequest의 0이 아닌 request_id입니다. 서버는 작업자가 이미 응답한 요청에 대해 취소 요청
을 전송할 수 있습니다. 이 경우 취소
요청은 무시해야 합니다.
취소 여부와 관계없이 취소가 아닌 각 WorkRequest 메시지에 정확히 한 번 응답해야 합니다. 서버가 취소 요청을 전송하면 작업자는
WorkResponse로 응답할 수 있으며 request_id가 설정되고 was_cancelled
필드가 true로 설정됩니다. 일반 WorkResponse 전송도 허용되지만
output 및 exit_code 필드는 무시됩니다.
WorkRequest에 대한 응답이 전송되면 작업자는 작업 디렉터리의
파일을 건드려서는 안 됩니다. 서버는 임시 파일을 포함한 파일을 자유롭게 정리할 수 있습니다.
작업자를 사용하는 규칙 만들기
또한 작업자가 실행할 작업을 생성하는 규칙을 만들어야 합니다. 작업자를 사용하는 Starlark 규칙을 만드는 것은 다른 규칙을 만드는 것과 같습니다.
또한 규칙에는 작업자 자체에 대한 참조가 포함되어야 하며 생성하는 작업에는 몇 가지 요구사항이 있습니다.
작업자 참조
작업자를 사용하는 규칙에는 작업자 자체를 참조하는 필드가 포함되어야 하므로 \*\_binary 규칙의 인스턴스를 만들어 작업자를 정의해야 합니다. 작업자의 이름이 MyWorker.Java인 경우
연결된 규칙은 다음과 같습니다.
java_binary(
name = "worker",
srcs = ["MyWorker.Java"],
)
그러면 작업자 바이너리를 참조하는 '작업자' 라벨이 생성됩니다. 그런 다음 작업자를 사용하는 규칙을 정의합니다. 이 규칙은 작업자 바이너리를 참조하는 속성을 정의해야 합니다.
빌드한 작업자 바이너리가 빌드의 최상위 수준에 있는 "work"라는 패키지에 있는 경우 속성 정의는 다음과 같습니다.
"worker": attr.label(
default = Label("//work:worker"),
executable = True,
cfg = "exec",
)
cfg = "exec"는 작업자가 타겟 플랫폼이 아닌
실행 플랫폼에서 실행되도록 빌드해야 함을 나타냅니다. 즉, 작업자는 빌드 중에 도구로 사용됩니다.
작업 작업 요구사항
작업자를 사용하는 규칙은 작업자가 실행할 작업을 만듭니다. 이러한 작업에는 몇 가지 요구사항이 있습니다.
"인수" 필드. 문자열 목록을 가져오며 마지막 문자열을 제외한 모든 문자열은 시작 시 작업자에 전달되는 인수입니다. '인수' 목록의 마지막 요소는
flag-file(@로 시작) 인수입니다. 작업자는 WorkRequest별로 지정된 플래그 파일에서 인수를 읽습니다. 규칙은 작업자의 시작 시 인수가 아닌 인수를 이 플래그 파일에 쓸 수 있습니다."실행 요구사항" 필드. 이 필드는
"supports-workers" : "1","supports-multiplex-workers" : "1", 또는 둘 다 포함하는 사전을 가져옵니다.'인수' 및 '실행 요구사항' 필드는 작업자에게 전송되는 모든 작업에 필요합니다. 또한 JSON 작업자가 실행해야 하는 작업에는
"requires-worker-protocol" : "json"이(가) 실행 요구사항 필드에 포함되어야 합니다."requires-worker-protocol" : "proto"도 유효한 실행 요구사항이지만 proto 작업자의 경우 기본값이므로 필요하지 않습니다.실행 요구사항에서
worker-key-mnemonic을 설정할 수도 있습니다. 이는 여러 작업 유형에 실행 파일을 재사용하고 이 작업자로 작업을 구분하려는 경우 유용할 수 있습니다.작업 중에 생성된 임시 파일은 작업자의 디렉터리에 저장해야 합니다. 이렇게 하면 샌드박싱이 사용 설정됩니다.
위에서 설명한 '작업자' 속성이 있는 규칙 정의를 입력, 출력을 나타내는 'srcs' 속성, 출력을 나타내는 'output' 속성, 작업자 시작 인수를 나타내는 'args' 속성 외에 ctx.actions.run 호출은 다음과 같습니다.
ctx.actions.run(
inputs=ctx.files.srcs,
outputs=[ctx.outputs.output],
executable=ctx.executable.worker,
mnemonic="someMnemonic",
execution_requirements={
"supports-workers" : "1",
"requires-worker-protocol" : "json"},
arguments=ctx.attr.args + ["@flagfile"]
)
다른 예시는 영구 작업자 구현을 참고하세요.
예
Bazel 코드베이스는 통합 테스트에 사용되는 JSON 작업자 예시 외에도 자바 컴파일러 작업자를 사용합니다.
올바른 콜백을 전달하여 스캐폴딩을 사용하여 자바 기반 도구를 작업자로 만들 수 있습니다.
작업자를 사용하는 규칙의 예시는 Bazel의 작업자 통합 테스트를 참고하세요.
외부 기여자는 다양한 언어로 작업자를 구현했습니다. Bazel 영구 작업자의 다국어 구현을 참고하세요. GitHub에서 더 많은 예시를 확인할 수 있습니다 !