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 behaviour আকারে একটি অ্যাবস্ট্রাকশন দেয়।
প্রসেস সংক্রান্ত অন্যান্য অ্যাবস্ট্রাকশন, যেমন Agent, GenServer, বা Task, এগুলো শুরু করার দুটি উপায় দেয়, হয় start অথবা start_link।