2017-04-20 63 views
1

我目前正在通過Elixir in Action,我正在對我的Todo應用程序代碼進行一些重構,以便更好地掌握OTP的主要部分。在主管中有邏輯可以嗎?

該應用程序使用一個數據庫,它只是將數據存儲在磁盤上的文件中。爲確保數據庫的目標文件夾存在,在數據庫進程中調用File.mkdir_p!(db_folder)。數據庫進程本身使用一堆工作進程來執行從磁盤實際存儲/檢索數據。

我目前的章節介紹了DIY流程註冊表,通過讓工作人員向註冊管理機構註冊並讓數據庫進程查找使用註冊表的工作人員來實施更加強大的監督樹,從而雙方都可以受到監督並會在失敗後繼續工作。

當Elixir 1.4出來時,我在補丁說明中看到了Registry模塊,所以我想我可能會重構應用程序並使用它。現在事實證明,數據庫進程並不需要知道數據庫用於存儲數據的文件夾。所以我把mkdir_p!叫出來,並考慮把它放在哪裏。兩個選項浮現在腦海中:

  1. DatabaseWorker
  2. DatabaseWorkerSupervisor

我個人比較傾向於第二種方法,因爲整個應用程序綁定,如果用戶沒有訪問權限反正崩潰持久性文件夾。但我不確定是否可以將邏輯放入Supervisor中。

根據情況是否將邏輯變爲主管不良風格或可接受?如果風格不好,我會在哪裏放置啓動邏輯,如果某個進程崩潰,我不想重複該啓動邏輯?


我的導師代碼:

defmodule Todo.DatabaseWorkerSupervisor do 
    use Supervisor 

    def start_link(db_folder) do 
    Supervisor.start_link(__MODULE__, db_folder) 
    end 

    def init(db_folder) do 
    File.mkdir_p!(db_folder) 

    processes = 
     for worker_id <- 1..3 do 
     worker(Todo.DatabaseWorker, [db_folder, worker_id], id: {:dbworker, worker_id}) 
     end 

    supervise(processes, strategy: :one_for_one) 
    end 
end 

回答

2

我在哪裏把啓動邏輯,我不想重複,如果一個進程崩潰?

從主管init調用此似乎是合乎邏輯的地方。 特別是如果你不希望它被重複。

也許代碼可以在另一個模塊中定義,但是從supervisor init調用它是有意義的,並且如果初始化失敗,讓主管崩潰。

+0

我選擇了這個答案,因爲它直接回答了原來的問題。但是請注意,[這個答案](http://stackoverflow.com/a/43519122/4050456)如果我想'Database'是'GenServer'也是很有意義的。 –

2

我寧願不把邏輯的主管。如果你開始把邏輯放在主管人員身上,你不能通過查看監督樹來推理崩潰/重新啓動。相反,我會建議下列監督樹:

suggested supervision tree

如果你把文件夾創建在DB根服務器的init,該DBSupervisor將等待init就移動到他的其他孩子之前回來。所以如果文件夾創建失敗,監督樹的其餘部分甚至不會產生。另外,如果DBSupervisor策略爲:rest_for_all,則DB代服務器中的任何故障都將重啓監督樹的其餘部分。

我知道這個答案可能看起來像是矯枉過正,但如果強調要糾正和學習,我認爲這是正確的方向。

一個重要說明。正如你所說的,通過註冊,你並不需要DB Gen服務器將任務從客戶端傳遞給工作人員,而且你是對的!雖然建議的監督樹看起來類似於註冊之前的監督樹,但您現在應該調用函數(可以在DB模塊中實現)來查詢註冊表並將任務直接從客戶機進程傳遞給工作人員。

+0

Sasa將數據庫模塊中的GenServer行爲從數據庫模塊中移除了幾頁,因爲它不再保持狀態,只是執行註冊表查找和委派。在那種情況下,你會在哪裏放置文件夾? –

+1

我認爲我的建議仍然存在,即使DB gen服務器負責的唯一的事情是在初始化時創建文件夾。再次,這是一個矯枉過正的問題,但想法是學習適當的OTP開發。但也許我錯了。讓我們看看還有什麼建議... – Nagasaki45

相關問題