Elixir 1.7 - GenServer

जेनेरेर व्यवहार




elixir

जेनेरेर व्यवहार

क्लाइंट-सर्वर रिलेशन के सर्वर को लागू करने के लिए एक व्यवहार मॉड्यूल।

एक GenServer किसी भी अन्य अमृत प्रक्रिया की तरह एक प्रक्रिया है और इसका उपयोग राज्य रखने, कोड को अतुल्यकालिक रूप से निष्पादित करने के लिए किया जा सकता है। इस मॉड्यूल का उपयोग करके कार्यान्वित एक सामान्य सर्वर प्रक्रिया (GenServer) का उपयोग करने का लाभ यह है कि इसमें इंटरफ़ेस फ़ंक्शंस का एक मानक सेट होगा और इसमें ट्रेसिंग और त्रुटि रिपोर्टिंग के लिए कार्यक्षमता शामिल होगी। यह एक पर्यवेक्षण वृक्ष में भी फिट होगा।

उदाहरण

GenServer व्यवहार आम क्लाइंट-सर्वर इंटरैक्शन को अमूर्त करता है। डेवलपर्स को केवल उन कॉलबैक और कार्यक्षमता को लागू करने की आवश्यकता होती है, जिनमें वे रुचि रखते हैं।

एक कोड उदाहरण के साथ शुरू करते हैं और फिर उपलब्ध कॉलबैक का पता लगाते हैं। कल्पना कीजिए कि हम एक जेनरवर चाहते हैं जो एक स्टैक की तरह काम करता है, जिससे हमें पुश और पॉप आइटम मिल सकते हैं:

defmodule Stack do
  use GenServer

  # Callbacks

  @impl true
  def init(stack) do
    {:ok, stack}
  end

  @impl true
  def handle_call(:pop, _from, [head | tail]) do
    {:reply, head, tail}
  end

  @impl true
  def handle_cast({:push, item}, state) do
    {:noreply, [item | state]}
  end
end

# Start the server
{:ok, pid} = GenServer.start_link(Stack, [:hello])

# This is the client
GenServer.call(pid, :pop)
#=> :hello

GenServer.cast(pid, {:push, :world})
#=> :ok

GenServer.call(pid, :pop)
#=> :world

हम start_link/2 को कॉल करके अपने Stack को शुरू करते हैं, सर्वर के कार्यान्वयन और इसके प्रारंभिक तर्क के साथ मॉड्यूल को पास करते हैं (एक सूची जिसमें स्टैक का प्रतिनिधित्व होता है आइटम :hello )। हम मुख्य रूप से दो प्रकार के संदेश भेजकर सर्वर के साथ बातचीत कर सकते हैं। कॉल संदेश सर्वर से एक उत्तर की उम्मीद करते हैं (और इसलिए तुल्यकालिक हैं) जबकि संदेश नहीं डाले जाते हैं।

हर बार जब आप एक GenServer.call/3 , तो ग्राहक एक संदेश भेजेगा जिसे handle_call/3 में handle_call/3 कॉलबैक द्वारा नियंत्रित किया जाना चाहिए। एक cast/2 संदेश handle_cast/2 द्वारा संभाला जाना चाहिए।

क्लाइंट / सर्वर API

यद्यपि ऊपर दिए गए उदाहरण में हमने GenServer.start_link/3 उपयोग किया है और दोस्तों को सीधे सर्वर से शुरू करने और संचार करने के लिए, अधिकांश समय हम सीधे GenServer फ़ंक्शन को कॉल नहीं करते हैं। इसके बजाय, हम सर्वर के सार्वजनिक एपीआई का प्रतिनिधित्व करने वाले नए कार्यों में कॉल लपेटते हैं।

यहाँ हमारे स्टैक मॉड्यूल का बेहतर कार्यान्वयन है:

defmodule Stack do
  use GenServer

  # Client

  def start_link(default) when is_list(default) do
    GenServer.start_link(__MODULE__, default)
  end

  def push(pid, item) do
    GenServer.cast(pid, {:push, item})
  end

  def pop(pid) do
    GenServer.call(pid, :pop)
  end

  # Server (callbacks)

  @impl true
  def init(stack) do
    {:ok, stack}
  end

  @impl true
  def handle_call(:pop, _from, [head | tail]) do
    {:reply, head, tail}
  end

  @impl true
  def handle_cast({:push, item}, state) do
    {:noreply, [item | state]}
  end
end

व्यवहार में, सर्वर और क्लाइंट दोनों फ़ंक्शन एक ही मॉड्यूल में होना आम है। यदि सर्वर और / या क्लाइंट कार्यान्वयन जटिल हो रहे हैं, तो आप उन्हें विभिन्न मॉड्यूल में रखना चाह सकते हैं।

GenServer और कॉलबैक का उपयोग करें

GenServer उपयोग करने पर 7 कॉलबैक लागू होने हैं। केवल आवश्यक कॉलबैक init/1

use GenServer child_spec/1 फ़ंक्शन को भी परिभाषित करता है, जिससे परिभाषित मॉड्यूल को पर्यवेक्षण के पेड़ के नीचे रखा जा सकता है। उत्पन्न child_spec/1 को निम्नलिखित विकल्पों के साथ अनुकूलित किया जा सकता है:

  • :id - बाल विनिर्देश पहचानकर्ता, वर्तमान मॉड्यूल में चूक
  • :start - बच्चे की प्रक्रिया कैसे शुरू करें ( __MODULE__.start_link/1 को कॉल करने के लिए चूक __MODULE__.start_link/1 )
  • :restart - जब बच्चे को फिर से शुरू किया जाना चाहिए, चूक करना :permanent
  • :shutdown - बच्चे को कैसे बंद किया जाए

उदाहरण के लिए:

use GenServer, restart: :transient, shutdown: 10_000

अधिक जानकारी के लिए Supervisor डॉक्स देखें।

नाम पंजीकरण

GenServer start_link/3 और start/3 , GenServer को प्रारंभ :name विकल्प के माध्यम से नाम दर्ज करने के लिए समर्थन करता है। पंजीकृत नाम भी समाप्ति पर स्वचालित रूप से साफ हो जाते हैं। समर्थित मूल्य हैं:

  • एक परमाणु - GenServer स्थानीय रूप से दिए गए नाम के साथ पंजीकृत है।

  • {:global, term} - GenServer :global मॉड्यूल में कार्यों का उपयोग करके दिए गए शब्द के साथ विश्व स्तर पर पंजीकृत है।

  • {:via, module, term} - GenServer दिए गए तंत्र और नाम के साथ पंजीकृत है। विकल्प के :via एक मॉड्यूल की अपेक्षा करता है जो register_name/2 , unregister_name/1 , whereis_name/1 और निर्यात register_name/2 send/2 । ऐसा ही एक उदाहरण है :global मॉड्यूल जो इन कार्यों का उपयोग प्रक्रियाओं के नामों और उनके संबद्ध पीआईडी ​​की सूची को रखने के लिए करता है जो कि अमृत नोड्स के नेटवर्क के लिए विश्व स्तर पर उपलब्ध हैं। अमृत ​​एक स्थानीय, विकेन्द्रीकृत और स्केलेबल रजिस्ट्री के साथ भी जहाज करता है जिसे स्थानीय रूप से संग्रहीत नामों के लिए रजिस्ट्री कहा जाता है जो गतिशील रूप से उत्पन्न होते हैं।

उदाहरण के लिए, हम अपने Stack सर्वर को स्थानीय रूप से शुरू और पंजीकृत कर सकते हैं:

# Start the server and register it locally with name MyStack
{:ok, _} = GenServer.start_link(Stack, [:hello], name: MyStack)

# Now messages can be sent directly to MyStack
GenServer.call(MyStack, :pop) #=> :hello

एक बार सर्वर चालू हो जाने के बाद, इस मॉड्यूल में शेष कार्य ( call/3 , cast/2 , और मित्र) भी एक परमाणु स्वीकार करेंगे, या कोई {:global, ...} या {:via, ...} tuples । सामान्य तौर पर, निम्नलिखित प्रारूप समर्थित हैं:

  • एक पीआईडी
  • एक परमाणु यदि सर्वर स्थानीय रूप से पंजीकृत है
  • {atom, node} यदि सर्वर स्थानीय रूप से किसी अन्य नोड पर पंजीकृत है
  • {:global, term} यदि सर्वर विश्व स्तर पर पंजीकृत है
  • {:via, module, name} यदि सर्वर एक वैकल्पिक रजिस्ट्री के माध्यम से पंजीकृत है {:via, module, name}

यदि स्थानीय रूप से गतिशील नामों को पंजीकृत करने में रुचि है, तो परमाणुओं का उपयोग न करें, क्योंकि परमाणु कभी भी कचरा-एकत्र नहीं होते हैं और इसलिए गतिशील रूप से उत्पन्न परमाणु कचरा-एकत्र नहीं होंगे। ऐसे मामलों के लिए, आप Registry मॉड्यूल का उपयोग करके अपनी खुद की स्थानीय रजिस्ट्री सेट कर सकते हैं।

"नियमित" संदेश प्राप्त करना

GenServer का लक्ष्य डेवलपर्स के लिए "रिसीव" लूप को अमूर्त करना है, स्वचालित रूप से सिस्टम संदेशों को संभालना, कोड परिवर्तन, तुल्यकालिक कॉल और बहुत कुछ का समर्थन करना है। इसलिए, आपको GenServer कॉलबैक के अंदर कभी भी अपने स्वयं के "प्राप्त" को कॉल नहीं करना चाहिए क्योंकि ऐसा करने से GenServer गलत व्यवहार करेगा।

call/3 और cast/2 द्वारा प्रदान किए गए सिंक्रोनस और एसिंक्रोनस संचार के अलावा, send/2 , send/2 Process.send_after/4 और इसी तरह के कार्यों द्वारा भेजे गए "नियमित" संदेशों को हैंडल handle_info/2 कॉलबैक के अंदर संभाला जा सकता है।

handle_info/2 का उपयोग कई स्थितियों में किया जा सकता है, जैसे कि Process.monitor/1 द्वारा भेजे गए DOWN संदेशों को संभालना। handle_info/2 लिए एक और उपयोग मामला आवधिक कार्य करने के लिए है, प्रक्रिया की मदद से। Process.send_after/4 :

defmodule MyApp.Periodically do
  use GenServer

  def start_link do
    GenServer.start_link(__MODULE__, %{})
  end

  @impl true
  def init(state) do
    schedule_work() # Schedule work to be performed on start
    {:ok, state}
  end

  @impl true
  def handle_info(:work, state) do
    # Do the desired work here
    schedule_work() # Reschedule once more
    {:noreply, state}
  end

  defp schedule_work() do
    Process.send_after(self(), :work, 2 * 60 * 60 * 1000) # In 2 hours
  end
end

GenServer का उपयोग करने के लिए कब (नहीं)

अब तक, हमने सीखा है कि एक GenServer को एक पर्यवेक्षित प्रक्रिया के रूप में इस्तेमाल किया जा सकता है जो सिंक और एसिंक्स कॉल को संभालता है। यह सिस्टम संदेशों को भी संभाल सकता है, जैसे कि आवधिक संदेश और मॉनिटरिंग इवेंट। GenServer प्रक्रियाओं का नाम भी दिया जा सकता है।

जेनरेवर, या सामान्य रूप से एक प्रक्रिया, का उपयोग आपके सिस्टम के रनटाइम विशेषताओं को मॉडल करने के लिए किया जाना चाहिए। एक GenServer को कोड संगठन के उद्देश्यों के लिए उपयोग नहीं किया जाना चाहिए।

अमृत ​​में, कोड संगठन मॉड्यूल और कार्यों द्वारा किया जाता है, प्रक्रियाएं आवश्यक नहीं हैं। उदाहरण के लिए, कल्पना कीजिए कि आप एक कैलकुलेटर को लागू कर रहे हैं और आप जेनरवर के पीछे सभी कैलकुलेटर ऑपरेशन लगाने का निर्णय लेते हैं:

def add(a, b) do
  GenServer.call(__MODULE__, {:add, a, b})
end

def handle_call({:add, a, b}, _from, state) do
  {:reply, a + b, state}
end

def handle_call({:subtract, a, b}, _from, state) do
  {:reply, a - b, state}
end

यह न केवल एक विरोधी प्रतिमान है क्योंकि यह कैलकुलेटर तर्क को पुष्ट करता है, बल्कि इसलिए भी है क्योंकि आपने कैलकुलेटर तर्क को एक एकल प्रक्रिया के पीछे रखा है, जो संभवतः आपके सिस्टम में एक अड़चन बन जाएगा, खासकर जब कॉल की संख्या बढ़ती है। इसके बजाय बस सीधे कार्यों को परिभाषित करें:

def add(a, b) do
  a + b
end

def subtract(a, b) do
  a - b
end

यदि आपको एक प्रक्रिया की आवश्यकता नहीं है, तो आपको एक प्रक्रिया की आवश्यकता नहीं है। केवल परिवर्तनशील गुणों के लिए प्रक्रियाओं का उपयोग करें, जैसे कि उत्परिवर्तनीय स्थिति, समरूपता और विफलताएं, कोड संगठन के लिए कभी नहीं।

के साथ डिबगिंग: sys मॉड्यूल

GenServers, विशेष प्रक्रियाओं के रूप में :sys मॉड्यूल का उपयोग करके डीबग किया जा सकता है। विभिन्न हुक के माध्यम से, यह मॉड्यूल डेवलपर्स को प्रक्रिया की स्थिति का पता लगाने और सिस्टम की घटनाओं का पता लगाने की अनुमति देता है जो इसके निष्पादन के दौरान होती हैं, जैसे कि संदेश प्राप्त, भेजे गए उत्तर और राज्य परिवर्तन।

आइए डीबगिंग के लिए उपयोग किए जाने वाले :sys मॉड्यूल से मूल कार्यों का पता लगाएं:

  • :sys.get_state/2 - प्रक्रिया की स्थिति की पुनर्प्राप्ति की अनुमति देता है। GenServer प्रक्रिया के मामले में, यह कॉलबैक मॉड्यूल राज्य होगा, क्योंकि कॉलबैक फ़ंक्शन में अंतिम तर्क के रूप में पारित किया गया था।
  • :sys.get_status/2 - प्रक्रिया की स्थिति की पुनर्प्राप्ति की अनुमति देता है। इस स्थिति में प्रक्रिया शब्दकोश शामिल है, अगर प्रक्रिया चल रही है या निलंबित है, माता-पिता पीआईडी, डीबगर राज्य, और व्यवहार मॉड्यूल की स्थिति, जिसमें कॉलबैक मॉड्यूल स्थिति शामिल है (जैसा कि लौटा दिया गया :sys.get_state/2 )। यह बदलना संभव है कि वैकल्पिक GenServer.format_status/2 कॉलबैक को परिभाषित करके इस स्थिति का प्रतिनिधित्व कैसे किया जाता है।
  • :sys.trace/3 - सभी सिस्टम इवेंट्स को प्रिंट करता है :stdio
  • :sys.statistics/3 - प्रक्रिया आँकड़ों के संग्रह का प्रबंधन करता है।
  • :sys.no_debug/2 - दी गई प्रक्रिया के लिए सभी डीबग हैंडलर को बंद कर देता है। एक बार डिबगिंग बंद करने के बाद हमारा काम करना बहुत महत्वपूर्ण है। अत्यधिक डिबग हैंडलर या जिन्हें बंद किया जाना चाहिए, लेकिन सिस्टम के प्रदर्शन को गंभीर रूप से नुकसान नहीं पहुंचा सकता है।
  • :sys.suspend/2 - एक प्रक्रिया को निलंबित करने की अनुमति देता है ताकि यह केवल सिस्टम संदेशों का जवाब दे लेकिन कोई अन्य संदेश नहीं। एक निलंबित प्रक्रिया के माध्यम से पुन :sys.resume/2 सक्रिय किया जा सकता है :sys.resume/2

आइए देखें कि हम पहले परिभाषित किए गए स्टैक सर्वर को डीबग करने के लिए उन कार्यों का उपयोग कैसे कर सकते हैं।

iex> {:ok, pid} = Stack.start_link([])
iex> :sys.statistics(pid, true) # turn on collecting process statistics
iex> :sys.trace(pid, true) # turn on event printing
iex> Stack.push(pid, 1)
*DBG* <0.122.0> got cast {push,1}
*DBG* <0.122.0> new state [1]
:ok
iex> :sys.get_state(pid)
[1]
iex> Stack.pop(pid)
*DBG* <0.122.0> got call pop from <0.80.0>
*DBG* <0.122.0> sent 1 to <0.80.0>, new state []
1
iex> :sys.statistics(pid, :get)
{:ok,
 [start_time: {{2016, 7, 16}, {12, 29, 41}},
  current_time: {{2016, 7, 16}, {12, 29, 50}},
  reductions: 117, messages_in: 2, messages_out: 0]}
iex> :sys.no_debug(pid) # turn off all debug handlers
:ok
iex> :sys.get_status(pid)
{:status, #PID<0.122.0>, {:module, :gen_server},
 [["$initial_call": {Stack, :init, 1},            # pdict
   "$ancestors": [#PID<0.80.0>, #PID<0.51.0>]],
  :running,                                       # :running | :suspended
  #PID<0.80.0>,                                   # parent
  [],                                             # debugger state
  [header: 'Status for generic server <0.122.0>', # module status
   data: [{'Status', :running}, {'Parent', #PID<0.80.0>},
     {'Logged events', []}], data: [{'State', [1]}]]]}

और अधिक जानें

यदि आप GenServers के बारे में और अधिक जानकारी प्राप्त करना चाहते हैं, तो Elixir Get Started Guide एक ट्यूटोरियल जैसा परिचय प्रदान करता है। Erlang में प्रलेखन और लिंक अतिरिक्त अंतर्दृष्टि भी प्रदान कर सकते हैं।

सारांश

प्रकार

debug()

डीबग विकल्प start* फ़ंक्शन द्वारा समर्थित

from()

कॉल अनुरोध के क्लाइंट का वर्णन करने वाला टपल

name()

GenServer नाम

on_start()

start* कार्यों का मान लौटाएँ

option()

start* कार्यों द्वारा उपयोग किए जाने वाले विकल्प मान

options()

start* कार्यों द्वारा उपयोग किए जाने वाले विकल्प

server()

सर्वर संदर्भ

कार्य

abcast (नोड्स \\ [नोड () | Node.list ()], नाम, अनुरोध)

सभी सर्वरों को स्थानीय रूप से निर्दिष्ट नोड्स में name रूप में पंजीकृत किया गया है

call/3

server लिए एक तुल्यकालिक कॉल करता server और इसके उत्तर की प्रतीक्षा करता है

cast/2

server लिए एक अतुल्यकालिक अनुरोध भेजता server

multi_call (नोड्स \\ [नोड () | Node.list ()], नाम, अनुरोध, टाइमआउट \\: अनंत)

निर्दिष्ट nodes में स्थानीय रूप से पंजीकृत सभी सर्वरों को कॉल करता है

उत्तर (ग्राहक, उत्तर)

एक ग्राहक को जवाब

start/3

लिंक के बिना एक GenServer प्रक्रिया शुरू करता है (एक पर्यवेक्षण वृक्ष के बाहर)

start_link/3

एक GenServer प्रक्रिया को वर्तमान प्रक्रिया से जुड़ा हुआ शुरू करता है

बंद करो (सर्वर, कारण \\: सामान्य, मध्यांतर \\: अनंत)

दिए गए reason साथ सर्वर को सिंक्रनाइज़ करता है

whereis(server)

दिए गए server साथ कोई प्रक्रिया जुड़ा नहीं है, तो जेनरवर प्रक्रिया की pid या {name, node} लौटाता है या nil server

कॉलबैक

code_change (old_vsn, राज्य, अतिरिक्त)

जब एक मॉड्यूल का एक अलग संस्करण लोड किया जाता है (हॉट कोड स्वैपिंग) और राज्य की शब्द संरचना को बदला जाना चाहिए तो GenServer की स्थिति को बदलने के लिए GenServer किया जाना चाहिए।

format_status (कारण, pdict_and_state)

GenServer स्थिति के एक स्वरूपित संस्करण को पुनः प्राप्त करने के लिए कुछ मामलों में शामिल किया गया

handle_call/3

सिंक्रोनस call/3 संदेशों को संभालने के लिए आमंत्रित किया गया। call/3 तब तक ब्लॉक रहेगा जब तक कोई जवाब नहीं मिलता है (जब तक कि कॉल आउट या नोड्स डिस्कनेक्ट नहीं हो जाते)

handle_cast/2

अतुल्यकालिक cast/2 संदेशों को संभालने के लिए आमंत्रित किया गया

handle_continue (जारी रखें, राज्य)

निर्देश continue लिए हैंडल किया गया

handle_info/2

अन्य सभी संदेशों को संभालने के लिए आमंत्रित किया गया

init(args)

सर्वर शुरू होने पर मंगवाया गया। start_link/3 या start/3 तब तक ब्लॉक रहेगा जब तक यह वापस नहीं आ जाता

समाप्त (कारण, राज्य)

जब सर्वर से बाहर निकलने वाला हो तो इनवाइट किया गया। इसके लिए आवश्यक कोई भी सफाई करनी चाहिए

प्रकार

डिबग ()

debug() :: [:trace | :log | :statistics | {:log_to_file, Path.t()}]

डीबग विकल्प start* फ़ंक्शन द्वारा समर्थित

(से)

from() :: {pid(), tag :: term()}

कॉल अनुरोध के क्लाइंट का वर्णन करने वाला टपल।

pid कॉलर की PID है और tag कॉल की पहचान करने के लिए उपयोग किया जाने वाला एक अनूठा शब्द है।

नाम ()

name() :: atom() | {:global, term()} | {:via, module(), term()}

GenServer नाम

on_start ()

on_start() ::
  {:ok, pid()} | :ignore | {:error, {:already_started, pid()} | term()}

start* कार्यों का मान लौटाएँ

विकल्प ()

option() ::
  {:debug, debug()}
  | {:name, name()}
  | {:timeout, timeout()}
  | {:spawn_opt, Process.spawn_opt()}

start* कार्यों द्वारा उपयोग किए जाने वाले विकल्प मान

विकल्प ()

options() :: [option()]

start* कार्यों द्वारा उपयोग किए जाने वाले विकल्प

सर्वर ()

server() :: pid() | name() | {atom(), node()}

सर्वर संदर्भ

कार्य

abcast (नोड्स \\ [नोड () | Node.list ()], नाम, अनुरोध)

abcast([node()], name :: atom(), term()) :: :abcast

सभी सर्वरों को स्थानीय रूप से निर्दिष्ट नोड्स में name रूप में पंजीकृत किया गया है।

यह फ़ंक्शन तुरंत लौटता है और उन नोड्स की उपेक्षा करता है जो मौजूद नहीं हैं, या जहां सर्वर नाम मौजूद नहीं है।

अधिक जानकारी के लिए multi_call/4 देखें।

कॉल (सर्वर, अनुरोध, टाइमआउट \\ 5000)

call(server(), term(), timeout()) :: term()

server लिए एक तुल्यकालिक कॉल करता server और इसके उत्तर की प्रतीक्षा करता है।

क्लाइंट सर्वर को दिए गए request को भेजता है और जवाब आने तक इंतजार करता है या एक टाइमआउट होता है। अनुरोध को संभालने के लिए handle_call/3 को सर्वर पर बुलाया जाएगा।

server इस मॉड्यूल के लिए प्रलेखन के "नाम पंजीकरण" अनुभाग में वर्णित किसी भी मान का हो सकता है।

समय समाप्ति

timeout शून्य से अधिक पूर्णांक है जो निर्दिष्ट करता है कि उत्तर के लिए प्रतीक्षा करने के लिए कितने मिलीसेकंड हैं, या परमाणु :infinity अनिश्चित काल तक प्रतीक्षा करने के लिए। डिफ़ॉल्ट मान 5000 । यदि निर्दिष्ट समय के भीतर कोई जवाब नहीं मिलता है, तो फ़ंक्शन कॉल विफल हो जाता है और कॉलर बाहर निकल जाता है। यदि कॉलर विफलता पकड़ता है और चालू रहता है, और सर्वर को उत्तर के साथ देर हो रही है, तो यह किसी भी समय बाद में कॉलर की संदेश कतार में आ सकता है। इस मामले में कॉल करने वाले को इसके लिए तैयार रहना चाहिए और ऐसे किसी भी कचरा संदेश को छोड़ देना चाहिए जो पहले तत्व के रूप में एक संदर्भ के साथ दो-तत्व ट्यूपल हैं।

कास्ट (सर्वर, अनुरोध)

cast(server(), term()) :: :ok

server लिए एक अतुल्यकालिक अनुरोध भेजता server

यह फ़ंक्शन हमेशा लौटता है :ok चाहे गंतव्य server (या नोड) मौजूद है। इसलिए यह अज्ञात है कि गंतव्य server ने संदेश को सफलतापूर्वक संभाला है या नहीं।

handle_cast/2 अनुरोध को संभालने के लिए सर्वर पर कॉल किया जाएगा। यदि server एक नोड पर है, जो अभी तक कॉलर एक से जुड़ा नहीं है, तो कॉल तब तक ब्लॉक होने वाला है जब तक कि कनेक्शन नहीं हो जाता। यह ओटीपी के :gen_server के व्यवहार से अलग है जहां इस मामले में एक अन्य प्रक्रिया द्वारा संदेश भेजा जाता है, जो अन्य नोड्स को आदेश से बाहर आने के लिए संदेश दे सकता है।

multi_call (नोड्स \\ [नोड () | Node.list ()], नाम, अनुरोध, टाइमआउट \\: अनंत)

multi_call([node()], name :: atom(), term(), timeout()) ::
  {replies :: [{node(), term()}], bad_nodes :: [node()]}

निर्दिष्ट nodes में स्थानीय रूप से पंजीकृत सभी सर्वरों को कॉल करता है।

सबसे पहले, request नोड में प्रत्येक नोड को भेजा जाता है; फिर, कॉलर उत्तर की प्रतीक्षा करता है। यह फ़ंक्शन एक दो-तत्व टपल लौटाता है {replies, bad_nodes} जहाँ:

  • replies - एक सूची है {node, reply} ट्यूपल्स की जहां node नोड है जिसने उत्तर दिया और reply उसका उत्तर है
  • bad_nodes - नोड्स की एक सूची है जो या तो मौजूद नहीं थी या जहां दिए गए name वाला सर्वर मौजूद नहीं था या जवाब नहीं दिया था

nodes नोड नामों की एक सूची है जिसमें अनुरोध भेजा जाता है। डिफ़ॉल्ट मान सभी ज्ञात नोड्स (इस नोड सहित) की सूची है।

उस देर के उत्तर से बचने के लिए (समय समाप्त होने के बाद) कॉलर की संदेश कतार को प्रदूषित करता है, वास्तविक कॉल करने के लिए एक बिचौलिया प्रक्रिया का उपयोग किया जाता है। देर से जवाब तब खारिज कर दिया जाएगा जब वे एक समाप्त प्रक्रिया में आते हैं।

उदाहरण

GenServer मॉड्यूल के लिए डॉक्स में वर्णित Stack जेनरवर को मानते हुए Stack रूप में पंजीकृत है :"[email protected]" GenServer :"[email protected]" और :"[email protected]" GenServer :"[email protected]" नोड्स:

GenServer.multi_call(Stack, :pop)
#=> {[{:"[email protected]", :hello}, {:"[email protected]", :world}], []}

उत्तर (ग्राहक, उत्तर)

reply(from(), term()) :: :ok

एक ग्राहक को जवाब।

इस फ़ंक्शन का उपयोग स्पष्ट रूप से क्लाइंट को एक उत्तर भेजने के लिए किया जा सकता है जिसे call/3 या multi_call/4 कहा जाता है जब उत्तर को handle_call/3 के वापसी मूल्य में निर्दिष्ट नहीं किया जा सकता है।

client होना चाहिए तर्क (दूसरा तर्क) जिसे handle_call/3 कॉलबैक द्वारा स्वीकार किया गया है। reply एक मनमाना शब्द है जिसे कॉल के वापसी मूल्य के रूप में ग्राहक को वापस दिया जाएगा।

ध्यान दें कि reply/2 को किसी भी प्रक्रिया से बुलाया जा सकता है, न कि केवल जेनरवर को जो मूल रूप से कॉल प्राप्त किया था (जब तक कि जेनसेवर from तर्क से किसी तरह संचार किया)।

यह फ़ंक्शन हमेशा लौटता है :ok

उदाहरण

def handle_call(:reply_in_one_second, from, state) do
  Process.send_after(self(), {:reply, from}, 1_000)
  {:noreply, state}
end

def handle_info({:reply, from}, state) do
  GenServer.reply(from, :one_second_has_passed)
  {:noreply, state}
end

प्रारंभ (मॉड्यूल, आर्ग, विकल्प \\ [])

start(module(), any(), options()) :: on_start()

लिंक के बिना एक GenServer प्रक्रिया शुरू करता है (एक पर्यवेक्षण वृक्ष के बाहर)।

अधिक जानकारी के लिए start_link/3 देखें।

start_link (मॉड्यूल, आर्ग, विकल्प \\ [])

start_link(module(), any(), options()) :: on_start()

एक GenServer प्रक्रिया को वर्तमान प्रक्रिया से जुड़ा हुआ शुरू करता है।

यह अक्सर पर्यवेक्षण पेड़ के हिस्से के रूप में GenServer को शुरू करने के लिए उपयोग किया जाता है।

एक बार सर्वर शुरू होने के बाद, दिए गए module के init(args) फ़ंक्शन को सर्वर को इनिशियलाइज़ करने के लिए तर्क के रूप में args साथ बुलाया जाता है। एक सिंक्रनाइज़ स्टार्ट-अप प्रक्रिया सुनिश्चित करने के लिए, यह फ़ंक्शन तब तक वापस नहीं आता है जब तक कि init(args) वापस नहीं आ जाता है।

ध्यान दें कि एक GenServer start_link/3 साथ शुरू हुआ, मूल प्रक्रिया से जुड़ा हुआ है और माता-पिता से दुर्घटनाओं के मामले में बाहर निकल जाएगा। GenServer इस वजह से भी बाहर निकल जाएगा :normal कारणों में अगर यह init(args) कॉलबैक से बाहर निकलने के लिए ट्रैप से कॉन्फ़िगर किया गया है।

विकल्प

  • :name - नाम पंजीकरण के लिए उपयोग किया जाता है जैसा कि GenServer लिए प्रलेखन में "नाम पंजीकरण" अनुभाग में GenServer

  • :timeout - यदि मौजूद है, तो सर्वर को दी गई संख्या को मिलीसेकेंड में खर्च करने की अनुमति दी जाती है या इसे समाप्त कर दिया जाएगा और प्रारंभ फ़ंक्शन वापस आ जाएगा {:error, :timeout}

  • :debug - यदि मौजूद है, तो :sys मॉड्यूल में संबंधित फ़ंक्शन लागू होता है

  • :spawn_opt - यदि मौजूद है, तो इसका मान अंतर्निहित प्रक्रिया के विकल्प के रूप में दिया जाता है जैसे कि Process.spawn/4

मान लौटाएं

यदि सर्वर सफलतापूर्वक बनाया और आरंभ किया गया है, तो यह फ़ंक्शन {:ok, pid} , जहां pid सर्वर का PID है, लौटाता है। यदि निर्दिष्ट सर्वर नाम के साथ एक प्रक्रिया पहले से मौजूद है, तो यह फ़ंक्शन उस प्रक्रिया के पीआईडी ​​के साथ {:error, {:already_started, pid}} है।

यदि init(args) कॉलबैक reason साथ विफल हो जाता reason , तो यह फ़ंक्शन {:error, reason} । अन्यथा, यदि यह {:stop, reason} या :ignore , तो प्रक्रिया समाप्त हो जाती है और यह फ़ंक्शन क्रमशः {:error, reason} या :ignore है।

बंद करो (सर्वर, कारण \\: सामान्य, मध्यांतर \\: अनंत)

stop(server(), reason :: term(), timeout()) :: :ok

दिए गए reason साथ सर्वर को सिंक्रनाइज़ करता है।

दिए गए server की terminate/2 कॉलबैक बाहर निकलने से पहले लागू किया जाएगा। यह फ़ंक्शन लौटाता है :ok यदि सर्वर दिए गए कारण से समाप्त हो जाता है तो :ok है; यदि यह किसी अन्य कारण से समाप्त होता है, तो कॉल बाहर निकलता है।

यह फ़ंक्शन त्रुटि रिपोर्टिंग के बारे में ओटीपी शब्दार्थ रखता है। यदि कारण इसके अलावा है :normal :shutdown या {:shutdown, _} , एक त्रुटि रिपोर्ट लॉग की गई है।

whereis (सर्वर)

whereis(server()) :: pid() | {atom(), node()} | nil

दिए गए server साथ कोई प्रक्रिया नहीं जुड़ा है, तो जेनरवर प्रक्रिया की pid या {name, node} लौटाता है या nil server

उदाहरण

उदाहरण के लिए, किसी सर्वर प्रक्रिया को देखने के लिए, उसकी निगरानी करें और उसे एक कास्ट भेजें:

process = GenServer.whereis(server)
monitor = Process.monitor(process)
GenServer.cast(process, :hello)

कॉलबैक

code_change (old_vsn, राज्य, अतिरिक्त) (वैकल्पिक)

code_change(old_vsn, state :: term(), extra :: term()) ::
  {:ok, new_state :: term()} | {:error, reason :: term()} | {:down, term()}
when old_vsn: term()

जब एक मॉड्यूल का एक अलग संस्करण लोड किया जाता है (हॉट कोड स्वैपिंग) और राज्य की शब्द संरचना को बदला जाना चाहिए तो GenServer की स्थिति को बदलने के लिए GenServer किया जाना चाहिए।

old_vsn उन्नयन के समय मॉड्यूल ( @vsn विशेषता द्वारा परिभाषित) का पिछला संस्करण है। पिछले संस्करण को अपग्रेड करते समय पहले तत्व के साथ 2-ट्यूपल में लपेटा गया है :down state GenServer की वर्तमान स्थिति है और राज्य को बदलने के लिए किसी भी अतिरिक्त डेटा की आवश्यकता होती है।

रिटर्निंग {:ok, new_state} राज्य को new_state और कोड परिवर्तन सफल होता है।

रिटर्निंग {:error, reason} कोड कारण के साथ कोड परिवर्तन में विफल रहता है और राज्य पिछली स्थिति के रूप में रहता है।

यदि code_change/3 उठाता है तो कोड परिवर्तन विफल हो जाता है और लूप अपनी पिछली स्थिति के साथ जारी रहेगा। इसलिए इस कॉलबैक में आमतौर पर साइड इफेक्ट्स नहीं होते हैं।

यह कॉलबैक वैकल्पिक है।

format_status (कारण, pdict_and_state) (वैकल्पिक)

format_status(reason, pdict_and_state :: list()) :: term()
when reason: :normal | :terminate

GenServer स्थिति के एक स्वरूपित संस्करण को पुनः प्राप्त करने के लिए कुछ मामलों में शामिल किया गया।

यह कॉलबैक GenServer की स्थिति की उपस्थिति को नियंत्रित करने के लिए उपयोगी हो सकता है। उदाहरण के लिए, यह बड़े राज्य की शर्तों को मुद्रित करने से बचने के लिए GenServer के राज्य के एक कॉम्पैक्ट प्रतिनिधित्व को वापस करने के लिए इस्तेमाल किया जा सकता है।

  • एक :sys.get_status/1 या :sys.get_status/2 को :sys.get_status/2 की स्थिति प्राप्त करने के लिए आमंत्रित किया जाता है; ऐसे मामलों में, reason है :normal

  • GenServer असामान्य रूप से समाप्त हो जाता है और एक त्रुटि लॉग करता है; ऐसे मामलों में, reason है :terminate

pdict_and_state एक दो-तत्वों की सूची [pdict, state] जहाँ pdict {key, value} की एक सूची है {key, value} जो GenServer की वर्तमान प्रक्रिया शब्दकोश का प्रतिनिधित्व GenServer और state GenServer की वर्तमान स्थिति है।

handle_call (अनुरोध, राज्य से) (वैकल्पिक)

handle_call(request :: term(), from(), state :: term()) ::
  {:reply, reply, new_state}
  | {:reply, reply, new_state, timeout() | :hibernate | {:continue, term()}}
  | {:noreply, new_state}
  | {:noreply, new_state, timeout() | :hibernate, {:continue, term()}}
  | {:stop, reason, reply, new_state}
  | {:stop, reason, new_state}
when reply: term(), new_state: term(), reason: term()

सिंक्रोनस call/3 संदेशों को संभालने के लिए आमंत्रित किया गया। call/3 तब तक ब्लॉक रहेगा जब तक कि कोई जवाब नहीं मिलता (जब तक कि कॉल आउट या नोड्स डिस्कनेक्ट नहीं हो जाते)।

request call/3 द्वारा भेजा गया अनुरोध संदेश है, call/3 करने वाले के PID युक्त 2-ट्यूपल है और एक शब्द जो विशिष्ट रूप से कॉल की पहचान करता है, और state GenServer की वर्तमान स्थिति है।

रिटर्निंग {:reply, reply, new_state} कॉल करने वाले को {:reply, reply, new_state} भेजता है और नए new_state साथ लूप जारी new_state

रिटर्निंग {:reply, reply, new_state, timeout} समान है {:reply, reply, new_state} को छोड़कर handle_info(:timeout, new_state) को timeout मिलीसेकंड के बाद कहा जाएगा यदि कोई मैसेज handle_info(:timeout, new_state) हैं।

रिटर्निंग {:reply, reply, new_state, :hibernate} {:reply, reply, new_state} समान है {:reply, reply, new_state} सिवाय प्रक्रिया हाइबरनेट होने के बाद और लूप तब भी जारी रहेगा, जब कोई मैसेज उसकी मैसेज कतार में हो। यदि एक संदेश पहले से ही संदेश कतार में है तो यह तुरंत होगा। GenServer हाइबरनेट करने से कचरा संग्रहण होता है और एक सतत ढेर निकल जाता है जो प्रक्रिया द्वारा उपयोग की जाने वाली मेमोरी को कम करता है।

रिटर्निंग {:reply, reply, new_state, {:continue, continue}} की तरह ही है {:reply, reply, new_state} सिर्फ handle_continue/2 को छोड़कर, वैल्यू continue तुरंत बाद वैल्यू आर्ग्यूमेंट के साथ continue

हाइबरनेटिंग का उपयोग आक्रामक रूप से नहीं किया जाना चाहिए क्योंकि बहुत अधिक समय कचरा एकत्र करने में खर्च किया जा सकता है। आम तौर पर इसका उपयोग केवल तब किया जाना चाहिए जब कोई संदेश जल्द ही अपेक्षित न हो और प्रक्रिया की स्मृति को कम करने के लिए लाभकारी दिखाया गया हो।

रिटर्निंग {:noreply, new_state} कॉलर को कोई प्रतिक्रिया नहीं भेजता है और नए स्टेट के साथ लूप जारी रखता है new_state । उत्तर को reply/2 साथ भेजा जाना चाहिए।

वापसी मूल्य का उपयोग नहीं करने के लिए तीन मुख्य उपयोग के मामले हैं:

  • कॉलबैक से लौटने से पहले जवाब देने के लिए क्योंकि प्रतिक्रिया धीमी गति से कॉल करने से पहले जानी जाती है।
  • कॉलबैक से लौटने के बाद जवाब देने के लिए क्योंकि प्रतिक्रिया अभी तक उपलब्ध नहीं है।
  • किसी अन्य प्रक्रिया से उत्तर देने के लिए, जैसे कार्य।

जब दूसरी प्रक्रिया से उत्तर दे रहा है तो GenServer को बाहर निकलना चाहिए, यदि दूसरी प्रक्रिया बिना उत्तर दिए बाहर निकल जाए क्योंकि कॉल करने वाले को उत्तर का इंतजार करने से रोक दिया जाएगा।

लौटकर {:noreply, new_state, timeout | :hibernate | {:continue, continue}} {:noreply, new_state, timeout | :hibernate | {:continue, continue}} {:noreply, new_state, timeout | :hibernate | {:continue, continue}} एक टाइमआउट, हाइबरनेशन को छोड़कर {:noreply, new_state} समान है :reply ट्यूपल के साथ होता है।

रिटर्निंग {:stop, reason, reply, new_state} लूप को रोकता है और terminate/2 को उचित reason और स्टेट new_state साथ बुलाया जाता है। फिर जवाब कॉल के जवाब के रूप में भेजा जाता है और प्रक्रिया उचित reason साथ बाहर निकलती है।

रिटर्निंग {:stop, reason, new_state} के समान है {:stop, reason, reply, new_state} सिवाय एक उत्तर भेजे नहीं।

यह कॉलबैक वैकल्पिक है। यदि किसी को कार्यान्वित नहीं किया जाता है, तो कॉल विफल होने पर सर्वर विफल हो जाएगा।

handle_cast (अनुरोध, राज्य) (वैकल्पिक)

handle_cast(request :: term(), state :: term()) ::
  {:noreply, new_state}
  | {:noreply, new_state, timeout() | :hibernate | {:continue, term()}}
  | {:stop, reason :: term(), new_state}
when new_state: term()

अतुल्यकालिक cast/2 संदेशों को संभालने के लिए आमंत्रित किया गया।

request एक cast/2 द्वारा भेजा गया अनुरोध संदेश है और state GenServer की वर्तमान स्थिति है।

लौटते हुए {:noreply, new_state} नए राज्य के साथ लूप जारी रखता है new_state

{:noreply, new_state, timeout} को वापस करना {:noreply, new_state, timeout} के समान है {:noreply, new_state} इसके अलावा handle_info(:timeout, new_state) को timeout मिलीसेकंड के बाद कहा जाएगा यदि कोई संदेश प्राप्त नहीं होता है।

रिटर्निंग {:noreply, new_state, :hibernate} के समान है {:noreply, new_state} लूप जारी रखने से पहले प्रक्रिया हाइबरनेट की जाती है। अधिक जानकारी के लिए handle_call/3 देखें।

लौटते हुए {:noreply, new_state, {:continue, continue}} {:noreply, new_state} समान है {:noreply, new_state} केवल handle_continue/2 को छोड़कर {:noreply, new_state} पहले तर्क के रूप में मान continue तुरंत बाद आह्वान किया जाएगा।

रिटर्निंग {:stop, reason, new_state} लूप को रोकता है और terminate/2 को reason और स्टेट new_state स्टेट के साथ कहा जाता है। प्रक्रिया उचित reason साथ बाहर निकलती है।

यह कॉलबैक वैकल्पिक है। यदि कोई कार्यान्वित नहीं किया जाता है, तो सर्वर विफल हो जाएगा यदि कोई कलाकार इसके खिलाफ प्रदर्शन करता है।

handle_continue (जारी रखें, राज्य) (वैकल्पिक)

handle_continue(continue :: term(), state :: term()) ::
  {:noreply, new_state}
  | {:noreply, new_state, timeout() | :hibernate | {:continue, term()}}
  | {:stop, reason :: term(), new_state}
when new_state: term()

निर्देश continue लिए हैंडल किया गया।

यह प्रारंभिक अवस्था के बाद काम करने के लिए या कई चरणों में कॉलबैक में कार्य विभाजन के लिए उपयोगी है, प्रक्रिया की स्थिति को अपडेट कर रहा है।

रिटर्न मान उसी तरह हैं जैसे कि handle_cast/2

यह कॉलबैक वैकल्पिक है। यदि कोई कार्यान्वित नहीं किया जाता है, तो एक निरंतर निर्देश का उपयोग करने पर सर्वर विफल हो जाएगा।

यह कॉलबैक केवल Erlang / OTP 21+ पर समर्थित है।

handle_info (संदेश, राज्य) (वैकल्पिक)

handle_info(msg :: :timeout | term(), state :: term()) ::
  {:noreply, new_state}
  | {:noreply, new_state, timeout() | :hibernate | {:continue, term()}}
  | {:stop, reason :: term(), new_state}
when new_state: term()

अन्य सभी संदेशों को संभालने के लिए आमंत्रित किया गया।

msg संदेश है और GenServer की वर्तमान स्थिति है। जब कोई टाइमआउट होता है तो संदेश है :timeout

रिटर्न मान उसी तरह हैं जैसे कि handle_cast/2

यह कॉलबैक वैकल्पिक है। यदि कोई लागू नहीं किया गया है, तो प्राप्त संदेश लॉग किया जाएगा।

init (args)

init(args :: term()) ::
  {:ok, state}
  | {:ok, state, timeout() | :hibernate | {:continue, term()}}
  | :ignore
  | {:stop, reason :: any()}
when state: any()

सर्वर शुरू होने पर मंगवाया गया। start_link/3 या start/3 तब तक ब्लॉक रहेगा जब तक यह वापस नहीं आ जाता।

args का तर्क शब्द (दूसरा तर्क) start_link/3 को दिया गया है।

रिटर्निंग {:ok, state} कारण start_link/3 वापस आएगा {:ok, pid} और इसके लूप में प्रवेश करने की प्रक्रिया।

रिटर्निंग {:ok, state, timeout} handle_info(:timeout, state) अलावा {:ok, state} समान है {:ok, state} यदि टाइमआउट के भीतर कोई संदेश नहीं मिलता है, तो timeout मिलीसेकंड के बाद कॉल किया जाएगा।

रिटर्निंग {:ok, state, :hibernate} {:ok, state} समान है {:ok, state} सिवाय लूप में प्रवेश करने से पहले प्रक्रिया को हाइबरनेट किया जाता है। हाइबरनेशन के बारे में अधिक जानकारी के लिए handle_call/3 देखें।

रिटर्निंग {:ok, state, {:continue, continue}} {:ok, state} समान है {:ok, state} सिवाय इसके कि लूप में प्रवेश करने के तुरंत बाद handle_continue/2 कॉलबैक पहले तर्क के रूप में continue मूल्य के साथ लागू किया जाएगा।

लौटना :ignore से start_link/3 वापस आ जाएगा :ignore और प्रक्रिया लूप में प्रवेश किए बिना या terminate/2 कॉल किए बिना सामान्य रूप से बाहर निकल जाएगी। यदि पर्यवेक्षण पेड़ के हिस्से का उपयोग किया जाता है, तो मूल पर्यवेक्षक प्रारंभ करने में विफल नहीं होगा और न ही तुरंत GenServer को पुनः आरंभ करने का प्रयास GenServer । पर्यवेक्षण वृक्ष के शेष भाग को शुरू किया जाएगा और इसलिए अन्य प्रक्रियाओं द्वारा GenServer आवश्यकता नहीं होनी चाहिए। इसे Supervisor.restart_child/2 साथ बाद में शुरू किया जा सकता है। चाइल्ड स्पेसिफिकेशन को पेरेंट सुपरवाइज़र में सहेजे जाने के कारण सुपरवाइज़र। इसके लिए मुख्य उपयोग के मामले हैं:

  • GenServer कॉन्फ़िगरेशन द्वारा अक्षम है, लेकिन बाद में सक्षम किया जा सकता है।
  • एक त्रुटि हुई और इसे Supervisor तुलना में एक अलग तंत्र द्वारा नियंत्रित किया जाएगा। पुनः आरंभ करने का प्रयास करने में देरी के बाद इस दृष्टिकोण में Supervisor.restart_child/2 को कॉल करना शामिल है।

रिटर्निंग {:stop, reason} कारण start_link/3 लौटेगा {:error, reason} और लूप में प्रवेश किए बिना या reason को terminate/2 करने की प्रक्रिया।

समाप्त (कारण, स्थिति) (वैकल्पिक)

terminate(reason, state :: term()) :: term()
when reason: :normal | :shutdown | {:shutdown, term()}

जब सर्वर से बाहर निकलने वाला हो तो इनवाइट किया गया। इसके लिए आवश्यक कोई भी सफाई करनी चाहिए।

reason बाहर निकलने का कारण है और state GenServer की वर्तमान स्थिति है। रिटर्न वैल्यू को नजरअंदाज किया जाता है।

यदि कॉलबैक ( init(args) को छोड़कर) निम्नलिखित में से कोई एक करता है, तो terminate/2 कहा जाता है:

  • रिटर्न a :stop tuple :stop
  • उठाता
  • कॉल Kernel.exit/1
  • अमान्य मान देता है
  • GenServer जाल बाहर निकलता है ( Process.flag/2 का उपयोग करके) और मूल प्रक्रिया एक निकास संकेत भेजता है

यदि एक पर्यवेक्षण वृक्ष का एक हिस्सा, एक GenServer का Supervisor इसे बंद करते समय एक निकास संकेत भेजेगा। एग्जिट सिग्नल बच्चे के विनिर्देशन में शटडाउन रणनीति पर आधारित है। यदि यह है :brutal_kill GenServer मारा जाता है और इसलिए terminate/2 नहीं कहा जाता है। हालाँकि, यदि यह एक समयबाह्य है तो Supervisor बाहर निकलने के संकेत भेजेगा :shutdown और GenServer पास terminate/2 को GenServer करने की GenServer होगी - यदि समय समाप्त होने के बाद भी प्रक्रिया जीवित है।

यदि GenServer को किसी भी प्रक्रिया से एक एक्जिट सिग्नल (जो कि :normal नहीं :normal ) प्राप्त होता है, जब वह बाहर नहीं निकलता है तो यह उसी कारण से अचानक बाहर निकल जाएगा और इसलिए कॉल terminate/2 । ध्यान दें कि एक प्रक्रिया डिफ़ॉल्ट रूप से बाहर नहीं निकलती है और एक लिंक प्रक्रिया से बाहर निकलने या उसके नोड के डिस्कनेक्ट होने पर एक निकास संकेत भेजा जाता है।

इसलिए यह गारंटी नहीं है कि जब GenServer बाहर निकलता है तो terminate/2 कहा जाता है। इस तरह के कारणों के लिए, हम आमतौर पर अलग-अलग प्रक्रियाओं में मॉनिटरिंग के उपयोग से या स्वयं लिंक द्वारा महत्वपूर्ण क्लीन-अप नियमों की अनुशंसा करते हैं। GenServer एक port (जैसे :gen_tcp.socket ) या File.io_device/0 नियंत्रित करने के लिए किसी क्लीनअप की आवश्यकता नहीं है, क्योंकि ये GenServer के एग्जिट सिग्नल प्राप्त करने पर बंद हो जाएंगे और terminate/2 में मैन्युअल रूप से बंद करने की आवश्यकता नहीं है ।

यदि reason नहीं है :normal :shutdown , और न ही {:shutdown, term} एक त्रुटि लॉग की गई है।

यह कॉलबैक वैकल्पिक है।

Original text