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

किसी समस्या की शिकायत करना सोर्स देखना Nightly · 8.0 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

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

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 में अनुरोध आईडी, शून्य या शून्य से ज़्यादा वाला बाहर निकलने का कोड, और आउटपुट मैसेज होता है. इस मैसेज में, अनुरोध को प्रोसेस करने या उसे लागू करने में हुई गड़बड़ियों के बारे में बताया जाता है. किसी भी टूल को कॉल करने पर, कर्मचारी को उसका 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
}

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

{
  "requestId" : 12,
}

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

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

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

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

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

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

रद्द नहीं किए गए हर WorkRequest मैसेज का जवाब एक बार दिया जाना चाहिए. भले ही, उसे रद्द किया गया हो या नहीं. सर्वर से रद्द करने का अनुरोध मिलने के बाद, वर्कर WorkResponse के साथ जवाब दे सकता है. इसमें request_id सेट होगा और was_cancelled फ़ील्ड को 'सही' पर सेट किया जाएगा. सामान्य 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" से पता चलता है कि वर्कर्स को टारगेट प्लैटफ़ॉर्म के बजाय, आपके रनिंग प्लैटफ़ॉर्म पर चलाने के लिए बनाया जाना चाहिए. इसका मतलब है कि वर्कर्स का इस्तेमाल, बिल्ड के दौरान टूल के तौर पर किया जाता है.

काम से जुड़ी कार्रवाई की ज़रूरी शर्तें

वर्कफ़्लो में वर्कर्स का इस्तेमाल करने वाला नियम, वर्कर्स के लिए कार्रवाइयां बनाता है. इन कार्रवाइयों के लिए, कुछ ज़रूरी शर्तें होती हैं.

  • "arguments" फ़ील्ड. यह स्ट्रिंग की सूची लेता है. इसमें आखिरी स्ट्रिंग को छोड़कर, सभी स्ट्रिंग, स्टार्टअप के समय वर्कर्स को भेजी जाने वाली आर्ग्युमेंट होती हैं. "आर्ग्युमेंट" सूची का आखिरी एलिमेंट, flag-file (@-पहले) आर्ग्युमेंट होता है. वर्कर्स, हर वर्क रिक्वेस्ट के आधार पर, तय की गई फ़्लैगफ़ाइल से आर्ग्युमेंट पढ़ते हैं. आपका नियम, इस फ़्लैगफ़ाइल में वर्कर्स के लिए, स्टार्टअप के अलावा अन्य आर्ग्युमेंट लिख सकता है.

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

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

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

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

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

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

वर्कर का इस्तेमाल करने वाले नियम का उदाहरण देखने के लिए, Bazel का वर्कर इंटिग्रेशन टेस्ट देखें.

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