स्थायी कर्मचारी बनाना

समस्या की शिकायत करें सोर्स देखें

लंबे समय तक काम करने वाले कर्मचारी आपके कारोबार को तेज़ बना सकते हैं. अगर आपके बिल्ड में बार-बार ऐसी कार्रवाइयां हैं जिनकी स्टार्टअप लागत ज़्यादा है या क्रॉस-ऐक्शन कैशिंग से फ़ायदा होगा, तो इन कार्रवाइयों को करने के लिए आपको अपने स्थायी कर्मचारी को लागू करना होगा.

Bazel सर्वर, stdin/stdout का इस्तेमाल करके वर्कर से संपर्क करता है. यह प्रोटोकॉल बफ़र या JSON स्ट्रिंग के इस्तेमाल के साथ काम करता है.

वर्कर इंप्लीमेंटेशन के दो हिस्से होते हैं:

कर्मचारी बनाना

लगातार काम करने वाले कर्मचारी कुछ ज़रूरी शर्तों को पूरा करते हैं:

  • यह अपने stdin से WorkRequests को पढ़ता है.
  • यह अपने stdout पर WorkResponses (और सिर्फ़ WorkResponse) लिखता है.
  • यह --persistent_worker फ़्लैग स्वीकार करता है. रैपर को --persistent_worker कमांड लाइन फ़्लैग की पहचान करनी चाहिए और यह तभी खुद को स्थायी बनाना चाहिए, जब उस फ़्लैग को पास कर दिया जाए. ऐसा न होने पर, रैपर को एक बार में कंपाइल करने के बाद बाहर निकलना होगा.

अगर आपका प्रोग्राम इन शर्तों को पूरा करता है, तो इसे स्थायी कर्मचारी के तौर पर इस्तेमाल किया जा सकता है!

काम के अनुरोध

WorkRequest में वर्कर के लिए आर्ग्युमेंट की सूची होती है, पाथ-डाइजेस्ट पेयर की सूची होती है, जो उन इनपुट को दिखाती है जिन्हें वर्कर ऐक्सेस कर सकता है (इसे लागू नहीं किया जाता, लेकिन इस जानकारी को कैश मेमोरी के लिए इस्तेमाल किया जा सकता है) और अनुरोध आईडी, जो सिंगलप्लेक्स वर्कर के लिए 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 में अनुरोध का आईडी, शून्य या बिना शून्य वाला एग्ज़िट कोड होता है. साथ ही, इसमें एक आउटपुट स्ट्रिंग होती है जो अनुरोध को प्रोसेस या उसे पूरा करते समय हुई किसी भी गड़बड़ी की जानकारी देती है. output फ़ील्ड में एक छोटा विवरण होता है; वर्कर के stderr में पूरे लॉग लिखे जा सकते हैं. हो सकता है कि वर्कर सिर्फ़ WorkResponses को stdout पर लिख सके, इसलिए आम तौर पर, वर्कर किसी भी टूल के stdout को stderr पर रीडायरेक्ट करता है.

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

प्रोटोबफ़ के लिए तय नियमों के मुताबिक, सभी फ़ील्ड वैकल्पिक होते हैं. हालांकि, Bazel को WorkRequest और उससे जुड़े WorkResponse की ज़रूरत होती है, ताकि उसका अनुरोध आईडी एक ही हो. इसलिए, अगर अनुरोध आईडी शून्य नहीं है, तो उसे बताना ज़रूरी है. यह एक मान्य WorkResponse है.

{
  "requestId" : 12,
}

0 का request_id "singleplex" अनुरोध को तब इस्तेमाल करता है, जब इस अनुरोध को अन्य अनुरोधों के साथ प्रोसेस नहीं किया जा सकता. सर्वर यह गारंटी देता है कि किसी वर्कर को सिर्फ़ request_id 0 या सिर्फ़ request_id शून्य से ज़्यादा वाले अनुरोध मिलते हैं. सिंगलप्लेक्स अनुरोध सीरियल में भेजे जाते हैं. उदाहरण के लिए, अगर सर्वर कोई जवाब मिलने तक दूसरा अनुरोध नहीं भेजता है (रद्द करने के अनुरोधों को छोड़कर, नीचे देखें).

ज़रूरी जानकारी

  • हर प्रोटोकॉल बफ़र की लंबाई varint फ़ॉर्मैट में होती है. ज़्यादा जानकारी के लिए, MessageLite.writeDelimitedTo() देखें.
  • JSON अनुरोध और रिस्पॉन्स, साइज़ इंडिकेटर से पहले नहीं आते हैं.
  • JSON के अनुरोध, प्रोटोबफ़ जैसी संरचना का इस्तेमाल करते हैं, लेकिन स्टैंडर्ड JSON का इस्तेमाल करते हैं और सभी फ़ील्ड के नामों के लिए ऊंट के केस का इस्तेमाल करते हैं.
  • बैकवर्ड और फ़ॉरवर्ड, दोनों के साथ काम करने वाली प्रॉपर्टी को प्रोटोबफ़ की तरह बनाए रखने के लिए, JSON वर्कर को इन मैसेज में अनजान फ़ील्ड को भी मंज़ूर करना होगा. साथ ही, छूटी हुई वैल्यू के लिए प्रोटोबफ़ डिफ़ॉल्ट का इस्तेमाल करना होगा.
  • Bazel, अनुरोधों को प्रोटोबफ़ के रूप में स्टोर करता है और उन्हें protobuf के JSON फ़ॉर्मैट का इस्तेमाल करके JSON में बदल देता है

रद्द किया जाना

कर्मचारी, काम पूरा होने से पहले काम के अनुरोधों को रद्द करने की अनुमति दे सकते हैं. यह डाइनैमिक एक्ज़ीक्यूशन के मामले में खास तौर पर फ़ायदेमंद होता है, क्योंकि लोकल एक्ज़ीक्यूशन को तेज़ रिमोट एक्ज़ीक्यूशन की वजह से नियमित रूप से रुकावट पैदा हो सकती है. रद्द करने की अनुमति देने के लिए, supports-worker-cancellation: 1 को execution-requirements फ़ील्ड (नीचे देखें) में जोड़ें और --experimental_worker_cancellation फ़्लैग सेट करें.

रद्द करने का अनुरोध, cancel फ़ील्ड सेट वाला WorkRequest होता है. इसी तरह, रद्द करने का अनुरोध, was_cancelled फ़ील्ड सेट वाला WorkResponse होता है. रद्द करने के अनुरोध या 'रद्द करें' रिस्पॉन्स में सिर्फ़ request_id होना चाहिए, जिससे पता चलता है कि किस अनुरोध को रद्द करना है. request_id फ़ील्ड, सिंगलप्लेक्स वर्कर के लिए 0 होगा या मल्टीप्लेक्स वर्कर के लिए पहले भेजे गए WorkRequest का गैर-0 request_id होगा. सर्वर उन अनुरोधों को रद्द करने के अनुरोध भेज सकता है जिन का वर्कर ने पहले ही जवाब दे दिया है. इस स्थिति में, रद्द करने के अनुरोध को अनदेखा करना होगा.

रद्द न किए जा सकने वाले हर WorkRequest मैसेज का जवाब सिर्फ़ एक बार दिया जाना चाहिए. भले ही, उस मैसेज को रद्द किया गया हो या नहीं. सर्वर से रद्द करने का अनुरोध भेजने के बाद, वर्कर request_id सेट करके WorkResponse जवाब दे सकता है और was_cancelled फ़ील्ड को 'सही' पर सेट कर सकता है. सामान्य WorkResponse भेजने का भी अनुरोध किया जाता है, लेकिन output और exit_code फ़ील्ड को अनदेखा कर दिया जाएगा.

WorkRequest के लिए जवाब भेजे जाने के बाद, वर्कर को अपनी वर्किंग डायरेक्ट्री में मौजूद फ़ाइलों को नहीं छूना चाहिए. सर्वर, फ़ाइलों को बिना शुल्क के हटा सकता है. इसमें, कुछ समय तक रहने वाली फ़ाइलें भी शामिल हैं.

वर्कर का इस्तेमाल करने वाला नियम बनाना

आपको एक ऐसा नियम भी बनाना होगा जो वर्कर की कार्रवाइयों को जनरेट करता हो. स्टारलार्क नियम बनाना, जिसमें वर्कर का इस्तेमाल किया जाता है, कोई दूसरा नियम बनाने जैसा ही है.

साथ ही, नियम में वर्कर का रेफ़रंस होना चाहिए और इससे होने वाली कार्रवाइयों की कुछ शर्तें भी होनी चाहिए.

वर्कर से कहा गया

वर्कर का इस्तेमाल करने वाले नियम में एक ऐसा फ़ील्ड होना चाहिए जो वर्कर से जुड़ा हो. इसलिए, आपको अपने वर्कर की पहचान करने के लिए, \*\_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 (@-preceded) आर्ग्युमेंट है. वर्कर, दिए गए फ़्लैगफ़ाइल से दिए गए तर्कों को हर WorkRequest के आधार पर पढ़ते हैं. आपका नियम इस फ़्लैगफ़ाइल में वर्कर के लिए नॉन-स्टार्टअप तर्क लिख सकता है.

  • "execution-requirements" फ़ील्ड, जिसमें "supports-workers" : "1", "supports-multiplex-workers" : "1" या दोनों शामिल होने वाली डिक्शनरी होती है.

    वर्कर को भेजी गई सभी कार्रवाइयों के लिए "तर्क" और "कार्रवाई करने की ज़रूरी शर्तें" फ़ील्ड ज़रूरी हैं. इसके अलावा, JSON कर्मचारियों को जो कार्रवाइयां करनी हैं उन्हें एक्ज़ीक्यूट करने की ज़रूरी शर्तों वाले फ़ील्ड में "requires-worker-protocol" : "json" को शामिल करना ज़रूरी है. "requires-worker-protocol" : "proto" भी लागू करने के लिए एक मान्य शर्त है. हालांकि, यह प्रोटो वर्कर के लिए ज़रूरी नहीं है, क्योंकि ये डिफ़ॉल्ट तौर पर सेट होते हैं.

    लागू करने की ज़रूरी शर्तों में, worker-key-mnemonic भी सेट किया जा सकता है. यह तब फ़ायदेमंद हो सकता है, जब कई तरह की कार्रवाइयों के लिए एक्ज़ीक्यूटेबल का फिर से इस्तेमाल किया जा रहा हो और आपको इस वर्कर की कार्रवाइयों में अंतर करना हो.

  • कार्रवाई के दौरान जनरेट हुई अस्थायी फ़ाइलें, कर्मचारी की डायरेक्ट्री में सेव की जानी चाहिए. इससे सैंडबॉक्सिंग चालू हो जाती है.

ऊपर बताए गए "worker" एट्रिब्यूट वाले नियम की परिभाषा के लिए, इनपुट को दिखाने वाली "srcs" एट्रिब्यूट, आउटपुट दिखाने वाली एक "आउटपुट" एट्रिब्यूट, और वर्कर स्टार्टअप आर्ग्युमेंट दिखाने वाली "आर्ग" एट्रिब्यूट के अलावा, 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 वर्कर के साथ-साथ, Java कंपाइलर वर्कर का इस्तेमाल करता है.

किसी भी Java-आधारित टूल को सही कॉलबैक देकर पास करके, उसे वर्कर के तौर पर बनाने के लिए, उसके स्कैफ़ाल्डिंग का इस्तेमाल किया जा सकता है.

ऐसे नियम के उदाहरण के लिए जिसमें वर्कर का इस्तेमाल किया जाता है, बैजल के कर्मचारियों के इंटिग्रेशन की जांच देखें.

Google से बाहर के लोगों ने, अलग-अलग भाषाओं में वर्कर को लागू किया है. Bazel के स्थायी वर्कर के लिए, पॉलीग्लोट तरीके से काम करने की सुविधा पर एक नज़र डालें. आपको GitHub पर कई और उदाहरण मिल सकते हैं!