2016-09-28 3 views
7

का ग्रेसफुल शट डाउन मैं जेनसेवर के साथ एक एलीक्सिर ऐप लिख रहा हूं जो बूट पर बाहरी एप्लिकेशन शुरू करता है और इसे बंद कर देता है और बाहर निकलने पर अन्य क्लीन-अप करता है। मैंने कॉलबैक और क्लीनअप कोड terminate/2 कॉलबैक में बूटअप कार्यक्षमता जोड़ा है।जेनसेवर

init कोड ठीक काम करता है जब GenServer शुरू कर दिया है, और जब :stop संकेत मैन्युअल भेज दिया जाता है terminate विधि भी कहा जाता है, लेकिन अप्रत्याशित शटडाउन और बीच में आता है के मामलों में (Ctrl + C मार के मामले में) आईईएक्स में, समाप्ति कोड नहीं कहा जाता है।


वर्तमान में, मैं मंच धागे, ब्लॉग पोस्ट और प्रलेखन के टन से अधिक चले गए हैं जिसमें शामिल हैं:

Elixir Docs - GenServers से:

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

इसलिए यह गारंटी नहीं है कि terminate/2 को GenServer बाहर निकलने पर कॉल किया जाता है। ऐसे कारणों से, हम आम तौर पर निगरानी या स्वयं लिंक द्वारा उपयोग की जाने वाली अलग प्रक्रियाओं में होने के लिए महत्वपूर्ण क्लीन-अप नियमों की अनुशंसा करते हैं।

लेकिन मैं बिल्कुल पता नहीं कैसे प्राप्त करने के लिए किसी और :init.stop, linked processes या कुछ भी इस के साथ काम करने के लिए (के बाद से इस GenServers के साथ मेरी पहली बार है) है।

defmodule MyAwesomeApp do 
    use GenServer 

    def start do 
    GenServer.start_link(__MODULE__, nil) 
    end 

    def init(state) do 
    # Do Bootup stuff 

    IO.puts "Starting: #{inspect(state)}" 
    {:ok, state} 
    end 

    def terminate(reason, state) do 
    # Do Shutdown Stuff 

    IO.puts "Going Down: #{inspect(state)}" 
    :normal 
    end 
end 

MyAwesomeApp.start 

उत्तर

4

terminate कॉलबैक लागू होने की संभावनाओं को बढ़ाने के लिए, सर्वर प्रक्रिया को बाहर निकलना चाहिए। हालांकि, इसके साथ ही, कुछ स्थितियों में कॉलबैक लागू नहीं किया जा सकता है (उदाहरण के लिए जब प्रक्रिया क्रूरता से मारे जाती है, या जब यह स्वयं दुर्घटनाग्रस्त हो जाती है)। अधिक जानकारी के लिए here देखें।

के रूप में उल्लेख किया है, अगर आप विनम्रता से बंद अपने सिस्टम, आप :init.stop, जो रिकर्सिवली बंद पर्यवेक्षण terminate कॉलबैक के कारण पेड़ लागू किया जा करने के लिए होगा आह्वान करना चाहिए करना चाहता हूँ।

जैसा कि आपने देखा है, अचानक बीएएम ओएस प्रक्रिया को बाहर निकालने का कोई तरीका नहीं है। यह एक स्व-परिभाषित संपत्ति है: बीईएएम प्रक्रिया अचानक समाप्त हो जाती है, इसलिए यह कोई कोड नहीं चला सकता है (क्योंकि इसे समाप्त कर दिया गया है)। इसलिए, अगर बीएएम को क्रूरता से समाप्त कर दिया गया है, तो कॉलबैक लागू नहीं किया जाएगा।

यदि बीएएम मरने पर आप बिना शर्त काम करना चाहते हैं, तो आपको इसे किसी अन्य ओएस प्रक्रिया से पहचानना होगा। मुझे यकीन नहीं है कि आपका सटीक उपयोग केस क्या है, लेकिन यह मानते हुए कि इसके लिए आपके पास कुछ मजबूत ज़रूरत है, फिर एक और बीम नोड चलाकर, उसी (या किसी अन्य) मशीन पर, यहां काम कर सकता है। फिर आपके पास एक नोड पर एक प्रक्रिया हो सकती है जो किसी अन्य नोड पर दूसरी प्रक्रिया की निगरानी करे, ताकि बीईएएम क्रूरता से मारने पर भी प्रतिक्रिया दे सके।

हालांकि, अगर आपको बिना शर्त रूप से कुछ क्लीनअप तर्क चलाने की आवश्यकता नहीं है, तो आपका जीवन आसान होगा, इसलिए विचार करें कि terminate में कोड एक जरूरी है, या बल्कि एक अच्छा है।

3

मैं तुम्हें दो समाधान का सुझाव कर सकते हैं:


यह मेरा कोड है।

दस्तावेज़ों में पहला उल्लेख किया गया है।

ध्यान दें कि एक प्रक्रिया बाहर निकलती नहीं है।

आपको अपने जेन सर्वर प्रक्रिया जाल से बाहर निकलना होगा। ऐसा करने के लिए:

Process.flag(:trap_exit, true) 

यह बाहर निकलने पर अपने प्रक्रिया कॉल terminate/2 बनाता है।

लेकिन एक और समाधान, ऊपरी पर्यवेक्षक को इस प्रारंभिकरण को सौंपना है। फिर पर्यवेक्षक जीन सर्वर के बाहरी अनुप्रयोग संदर्भ पास करते हैं। लेकिन यहां, आपके पास terminate नहीं है- यदि आवश्यक हो तो बाहरी एप्लिकेशन से बाहर निकलने के लिए कॉलबैक की तरह। जब पर्यवेक्षक बंद हो जाता है, तो बाहरी एप्लिकेशन को मार दिया जाएगा।

+0

'Process.flag (: trap_exit, true) 'मेरे लिए काम नहीं करता है। क्या आप कृपया बता सकते हैं कि मुझे इसे एक जेन्सेवर में कहां जाना है? – Sheharyar

+0

आपको इसे प्रक्रिया में सेट करना चाहिए, जिसका अर्थ है 'init/1' – vfsoraki

+0

कोशिश की गई है कि यह काम नहीं करता है। – Sheharyar

0

अपने यह iex और Process.flag(:trap_exit, true) में काम करने के लिए काम नहीं कर रहा प्राप्त करने की कोशिश करते हैं, तो सुनिश्चित करें कि आप GenServer.start_link के बजाय का उपयोग कर रहे अन्यथा खोल प्रक्रिया दुर्घटना होगा और फंसाने कोई फर्क नहीं होगा।

`` `

defmodule सर्वर

use GenServer 
require Logger 

def start() do 
    GenServer.start(__MODULE__, [], []) 
end 


def init(_) do 
    Logger.info "starting" 
    Process.flag(:trap_exit, true) # your trap_exit call should be here 
    {:ok, :some_state} 
end 

# handle the trapped exit call 
def handle_info({:EXIT, _from, reason}, state) do 
    Logger.info "exiting" 
    cleanup(reason, state) 
    {:stop, reason, state} # see GenServer docs for other return types 
end 

# handle termination 
def terminate(reason, state) do 
    Logger.info "terminating" 
    cleanup(reason, state) 
    state 
end 

defp cleanup(_reason, _state) do 
    # Cleanup whatever you need cleaned up 
end 

अंत

` ``

आईईएक्स में आप अब एक फंस बाहर निकलने देखना चाहिए है:

यहाँ एक उदाहरण है कॉल

iex> {:ok, pid} = GenServer.start() iex> Process.exit(pid, :something_bad)