Elixir के प्रोसेस अलग-अलग रहते हैं और डिफॉल्ट रूप से कुछ भी साझा नहीं करते। जब कोई ऐसा चाइल्ड प्रोसेस क्रैश होता है जो किसी से लिंक नहीं है, तो उसका पैरेंट प्रोसेस प्रभावित नहीं होता।
parent_pid =
spawn(fn ->
spawn(fn -> raise "oops" end)
receive do
message -> IO.inspect(message, label: "received message")
end
end)
# => 20:03:08.405 [error] Process #PID<0.153.0> raised an exception
# ** (RuntimeError) oops
# (stdlib 3.13.2) erl_eval.erl:678: :erl_eval.do_apply/6
Process.alive?(parent_pid)
# => true
इस व्यवहार को प्रोसेस को एक-दूसरे से लिंक करके बदला जा सकता है। अगर दो प्रोसेस लिंक हों, तो एक प्रोसेस में आई विफलता दूसरे प्रोसेस तक पहुँचा दी जाती है। लिंक दो-तरफा होते हैं।
parent_pid =
spawn(fn ->
spawn_link(fn -> raise "oops" end)
receive do
message ->
IO.inspect(message, label: "received message")
end
end)
# => 20:05:34.125 [error] Process #PID<0.171.0> raised an exception
# ** (RuntimeError) oops
# (stdlib 3.13.2) erl_eval.erl:678: :erl_eval.do_apply/6
Process.alive?(parent_pid)
# => false
प्रोसेस ऐसे भी बनाए जा सकते हैं जो पहले से ही कॉल करने वाले प्रोसेस से लिंक हों। इसके लिए spawn_link/1 इस्तेमाल होता है, जो एक एटॉमिक ऑपरेशन है। या उन्हें बाद में Process.link/1 से लिंक किया जा सकता है।
Process.info/1 की मदद से आप देख सकते हैं कि इस समय किसी प्रोसेस से कौन-कौन से प्रोसेस लिंक हैं (और अब भी चल रहे हैं)।
pid = spawn_link(fn -> :timer.sleep(50_000) end)
# => #PID<0.126.0>
self()
|> Process.info()
|> Keyword.get(:links)
# => [#PID<0.126.0>]
जब आप समानांतर काम कर रहे हों और किसी एक हिस्से के पूरा न हो पाने पर बाकी हिस्सों को जारी नहीं रखना हो, तब प्रोसेस को लिंक करना उपयोगी हो सकता है।
लिंक करने का इस्तेमाल प्रोसेस की निगरानी के लिए भी किया जा सकता है। अगर कोई प्रोसेस एक्ज़िट ट्रैप करता है, तो जिस प्रोसेस से वह लिंक है, उसके क्रैश होने पर वह खुद क्रैश नहीं होगा। इसके बजाय उसे क्रैश के बारे में एक संदेश मिलेगा। इससे वह क्रैश को आसानी से संभाल सकता है, जैसे क्रैश हुए प्रोसेस को फिर से शुरू करके।
किसी प्रोसेस को Process.flag(:trap_exit, true) कॉल करके एक्ज़िट ट्रैप करने के लिए सेट किया जा सकता है। ध्यान दीजिए कि Process.flag/2 फ्लैग की पुरानी वैल्यू लौटाता है, नई नहीं।
फ्लैग की मौजूदा वैल्यू Process.info/1 की मदद से देखी जा सकती है।
pid
|> Process.info()
|> Keyword.get(:trap_exit)
# => false
अगर कोई लिंक किया हुआ प्रोसेस क्रैश हो जाए, तो प्रोसेस को भेजा जाने वाला संदेश {:EXIT, from, reason} पैटर्न से मेल खाएगा, जहाँ from एक PID है। अगर reason एटम :normal के अलावा कुछ और है, तो इसका मतलब है कि प्रोसेस क्रैश हुआ या उसे बलपूर्वक बंद किया गया।
parent_pid =
spawn(fn ->
Process.flag(:trap_exit, true)
spawn_link(fn -> raise "oops" end)
receive do
message ->
IO.inspect(message, label: "received message")
# do something else,
# to demonstrate that the process stays alive
:timer.sleep(50_000)
end
end)
# => 20:05:34.125 [error] Process #PID<0.295.0> raised an exception
# ** (RuntimeError) oops
# (stdlib 3.13.2) erl_eval.erl:678: :erl_eval.do_apply/6
# received message: {:EXIT, #PID<0.295.0>,
# {%RuntimeError{message: "oops"},
# [{:erl_eval, :do_apply, 6, [file: 'erl_eval.erl', line: 678]}]}}
Process.alive?(parent_pid)
# => true
ध्यान रखिए कि एक्ज़िट ट्रैप करने से प्रोसेस अपने सभी लिंक किए हुए प्रोसेस के क्रैश से अप्रभावित रहता है, और अगर एक्ज़िट संदेश पढ़े न जाएँ, तो वे प्रोसेस के मेलबॉक्स में जमा हो सकते हैं। इस कारण आपको एक्ज़िट ट्रैप करने वाले प्रोसेस से लिंक जुड़े सभी प्रोसेस का ध्यान रखना चाहिए। आमतौर पर, एक्ज़िट ट्रैप करने वाले प्रोसेस सिर्फ दूसरे प्रोसेस की निगरानी करते हैं और कुछ और नहीं करते।
व्यवहार में, आपको शुरू से अपना निगरानी करने वाला प्रोसेस खुद नहीं बनाना पड़ेगा। इस तरह की सुविधा के लिए Elixir Supervisor बिहेवियर के रूप में एक एब्स्ट्रैक्शन देता है।
प्रोसेस से जुड़े दूसरे एब्स्ट्रैक्शन, जैसे Agent, GenServer, या Task, उन्हें शुरू करने के दो तरीके देते हैं: start या start_link।