Membuat Pekerja Persisten

Laporkan masalah Lihat sumber Nightly · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

Pekerja persisten dapat mempercepat build Anda. Jika Anda memiliki tindakan berulang dalam build yang memiliki biaya startup tinggi atau akan mendapatkan manfaat dari penyiapan cache lintas-tindakan, Anda dapat menerapkan pekerja persisten Anda sendiri untuk melakukan tindakan ini.

Server Bazel berkomunikasi dengan pekerja menggunakan stdin/stdout. Server ini mendukung penggunaan string JSON atau buffer protokol.

Implementasi pekerja memiliki dua bagian:

Membuat pekerja

Pekerja persisten memenuhi beberapa persyaratan:

  • Membaca WorkRequests dari stdin-nya.
  • API ini menulis WorkResponses (dan hanya WorkResponse) ke stdout-nya.
  • Properti ini menerima tanda --persistent_worker. Wrapper harus mengenali tanda command line --persistent_worker dan hanya menjadikannya persisten jika tanda tersebut diteruskan, jika tidak, wrapper harus melakukan kompilasi sekali jalan dan keluar.

Jika program Anda memenuhi persyaratan ini, program tersebut dapat digunakan sebagai pekerja persisten.

Permintaan pekerjaan

WorkRequest berisi daftar argumen ke pekerja, daftar pasangan path-digest yang merepresentasikan input yang dapat diakses pekerja (ini tidak diterapkan, tetapi Anda dapat menggunakan info ini untuk melakukan caching), dan ID permintaan, yaitu 0 untuk pekerja simpleks.

CATATAN: Meskipun spesifikasi buffer protokol menggunakan "snake case" (request_id), protokol JSON menggunakan "camel case" (requestId). Dokumen ini menggunakan camel case dalam contoh JSON, tetapi snake case saat membahas kolom terlepas dari protokol.

{
  "arguments" : ["--some_argument"],
  "inputs" : [
    { "path": "/path/to/my/file/1", "digest": "fdk3e2ml23d"},
    { "path": "/path/to/my/file/2", "digest": "1fwqd4qdd" }
 ],
  "requestId" : 12
}

Kolom verbosity opsional dapat digunakan untuk meminta output proses debug tambahan dari pekerja. Pekerja sepenuhnya berhak menentukan apa dan bagaimana outputnya. Nilai yang lebih tinggi menunjukkan output yang lebih panjang. Meneruskan tanda --worker_verbose ke Bazel menetapkan kolom verbosity ke 10, tetapi nilai yang lebih kecil atau lebih besar dapat digunakan secara manual untuk jumlah output yang berbeda.

Kolom sandbox_dir opsional hanya digunakan oleh pekerja yang mendukung sandbox multiplex.

Respons kerja

WorkResponse berisi ID permintaan, kode keluar nol atau bukan nol, dan pesan output yang menjelaskan error yang terjadi dalam memproses atau mengeksekusi permintaan. Pekerja harus merekam stdout dan stderr dari alat apa pun yang dipanggilnya dan melaporkannya melalui WorkResponse. Menulisnya ke stdout dari proses pekerja tidak aman, karena akan mengganggu protokol pekerja. Menulisnya ke stderr proses pekerja aman, tetapi hasilnya dikumpulkan dalam file log per pekerja, bukan dikaitkan dengan tindakan individual.

{
  "exitCode" : 1,
  "output" : "Action failed with the following message:\nCould not find input
    file \"/path/to/my/file/1\"",
  "requestId" : 12
}

Sesuai dengan norma untuk protobuf, semua kolom bersifat opsional. Namun, Bazel memerlukan WorkRequest dan WorkResponse yang sesuai, agar memiliki ID permintaan yang sama, sehingga ID permintaan harus ditentukan jika bukan nol. Ini adalah WorkResponse yang valid.

{
  "requestId" : 12,
}

request_id 0 menunjukkan permintaan "singleplex", yang digunakan saat permintaan ini tidak dapat diproses secara paralel dengan permintaan lain. Server menjamin bahwa pekerja tertentu menerima permintaan dengan hanya request_id 0 atau hanya request_id lebih besar dari nol. Permintaan singleplex dikirim secara serial, misalnya jika server tidak mengirim permintaan lain hingga menerima respons (kecuali untuk permintaan pembatalan, lihat di bawah).

Catatan

  • Setiap buffer protokol didahului dengan panjangnya dalam format varint (lihat MessageLite.writeDelimitedTo().
  • Permintaan dan respons JSON tidak didahului oleh indikator ukuran.
  • Permintaan JSON mempertahankan struktur yang sama dengan protobuf, tetapi menggunakan JSON standar dan menggunakan camel case untuk semua nama kolom.
  • Untuk mempertahankan properti kompatibilitas mundur dan maju yang sama seperti protobuf, pekerja JSON harus mentoleransi kolom yang tidak diketahui dalam pesan ini, dan menggunakan default protobuf untuk nilai yang tidak ada.
  • Bazel menyimpan permintaan sebagai protobuf dan mengonversinya ke JSON menggunakan format JSON protobuf

Pembatalan

Pekerja dapat secara opsional mengizinkan permintaan kerja dibatalkan sebelum selesai. Hal ini sangat berguna sehubungan dengan eksekusi dinamis, di mana eksekusi lokal dapat terganggu secara rutin oleh eksekusi jarak jauh yang lebih cepat. Untuk mengizinkan pembatalan, tambahkan supports-worker-cancellation: 1 ke kolom execution-requirements (lihat di bawah) dan tetapkan flag --experimental_worker_cancellation.

Permintaan pembatalan adalah WorkRequest dengan kolom cancel yang ditetapkan (dan respons pembatalan adalah WorkResponse dengan kolom was_cancelled yang ditetapkan). Satu-satunya kolom lain yang harus ada dalam permintaan pembatalan atau respons pembatalan adalah request_id, yang menunjukkan permintaan mana yang akan dibatalkan. Kolom request_id akan bernilai 0 untuk pekerja simpleks atau request_id non-0 dari WorkRequest yang sebelumnya dikirim untuk pekerja multipleks. Server dapat mengirim permintaan pembatalan untuk permintaan yang telah direspons oleh pekerja, dalam hal ini permintaan pembatalan harus diabaikan.

Setiap pesan WorkRequest yang tidak dibatalkan harus dijawab tepat satu kali, baik dibatalkan atau tidak. Setelah server mengirim permintaan pembatalan, pekerja dapat merespons dengan WorkResponse yang request_id-nya ditetapkan dan kolom was_cancelled ditetapkan ke benar (true). Pengiriman WorkResponse reguler juga dapat diterima, tetapi kolom output dan exit_code akan diabaikan.

Setelah respons dikirim untuk WorkRequest, pekerja tidak boleh menyentuh file di direktori kerjanya. Server bebas membersihkan file, termasuk file sementara.

Membuat aturan yang menggunakan pekerja

Anda juga harus membuat aturan yang menghasilkan tindakan yang akan dilakukan oleh pekerja. Membuat aturan Starlark yang menggunakan pekerja sama seperti membuat aturan lainnya.

Selain itu, aturan harus berisi referensi ke pekerja itu sendiri, dan ada beberapa persyaratan untuk tindakan yang dihasilkannya.

Merujuk ke pekerja

Aturan yang menggunakan pekerja harus berisi kolom yang merujuk ke pekerja itu sendiri, jadi Anda harus membuat instance aturan \*\_binary untuk menentukan pekerja. Jika pekerja Anda bernama MyWorker.Java, ini mungkin merupakan aturan terkait:

java_binary(
    name = "worker",
    srcs = ["MyWorker.Java"],
)

Tindakan ini akan membuat label "worker", yang merujuk ke biner pekerja. Kemudian, Anda akan menentukan aturan yang menggunakan pekerja. Aturan ini harus menentukan atribut yang merujuk ke biner pekerja.

Jika biner pekerja yang Anda buat berada dalam paket bernama "work", yang berada di tingkat teratas build, ini mungkin definisi atributnya:

"worker": attr.label(
    default = Label("//work:worker"),
    executable = True,
    cfg = "exec",
)

cfg = "exec" menunjukkan bahwa pekerja harus dibuat untuk berjalan di platform eksekusi Anda, bukan di platform target (yaitu, pekerja digunakan sebagai alat selama build).

Persyaratan tindakan kerja

Aturan yang menggunakan pekerja membuat tindakan yang harus dilakukan pekerja. Tindakan ini memiliki beberapa persyaratan.

  • Kolom "arguments". Tindakan ini mengambil daftar string, yang semuanya kecuali yang terakhir adalah argumen yang diteruskan ke pekerja saat startup. Elemen terakhir dalam daftar "arguments" adalah argumen flag-file (diawali dengan @). Pekerja membaca argumen dari flagfile yang ditentukan berdasarkan per-WorkRequest. Aturan Anda dapat menulis argumen non-startup untuk pekerja ke file tanda ini.

  • Kolom "execution-requirements", yang menggunakan kamus yang berisi "supports-workers" : "1", "supports-multiplex-workers" : "1", atau keduanya.

    Kolom "arguments" dan "execution-requirements" diperlukan untuk semua tindakan yang dikirim ke pekerja. Selain itu, tindakan yang harus dijalankan oleh pekerja JSON harus menyertakan "requires-worker-protocol" : "json" di kolom persyaratan eksekusi. "requires-worker-protocol" : "proto" juga merupakan persyaratan eksekusi yang valid, meskipun tidak diperlukan untuk pekerja proto, karena merupakan default.

    Anda juga dapat menetapkan worker-key-mnemonic dalam persyaratan eksekusi. Hal ini mungkin berguna jika Anda menggunakan kembali file yang dapat dieksekusi untuk beberapa jenis tindakan dan ingin membedakan tindakan berdasarkan pekerja ini.

  • File sementara yang dihasilkan selama tindakan harus disimpan ke direktori pekerja. Tindakan ini mengaktifkan sandbox.

Dengan asumsi definisi aturan dengan atribut "worker" yang dijelaskan di atas, selain atribut "srcs" yang merepresentasikan input, atribut "output" yang merepresentasikan output, dan atribut "args" yang merepresentasikan argumen startup worker, panggilan ke ctx.actions.run mungkin berupa:

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"]
 )

Untuk contoh lainnya, lihat Menerapkan pekerja persisten.

Contoh

Basis kode Bazel menggunakan pekerja compiler Java, selain pekerja JSON contoh yang digunakan dalam pengujian integrasi kami.

Anda dapat menggunakan scaffolding untuk mengubah alat berbasis Java apa pun menjadi pekerja dengan meneruskan callback yang benar.

Untuk contoh aturan yang menggunakan pekerja, lihat uji integrasi pekerja Bazel.

Kontributor eksternal telah menerapkan pekerja dalam berbagai bahasa; lihat Implementasi pekerja persisten Bazel poliglota. Anda dapat menemukan banyak contoh lainnya di GitHub.