2016-10-24 8 views
0

私は例えば、単一の項目のための機能を実装しGenServerを持っている:Elixir GenServerハンドラ内から他の関数​​を呼び出す方法は?

def handle_call({:sync, id}, _from, state) do 
    ## update data 
    {:reply, data, sync} 
end 

は今、私は複数のID、例えばのために、この機能を処理したい:

def handle_call({:sync_all, ids}, _from, state) do 
    ## call sync for each id 
    data = Enum.map(ids, fn(id) -> 
     GenServer.call(self(), {:sync, id}) 
    end) 
    ## Further reduce down data to stats 
    {:reply, data, sync} 
end 

しかし、これは私に言っては動作しません。プロセスが自身を呼び出そうとしたことを示します。

これは、ブロックする性質がcallであることが必要であると仮定します。しかし、sync_allバージョンでcastを使用すると同じことが起こります。

私の質問は次のとおりです。handle_callまたはhandle_castの中から他のGenServerタスクをどのように呼び出すことができますか?あなたは、通常このような場合にはどうなるのか

+0

'cast'は' handle_call'の内部で動作するはずです。あなたはそれを行い、あなたのために働かなかったコードのバージョンを投稿できますか? – Dogbert

答えて

7

は、別の関数に共通のロジックを抽出することである。

def handle_call({:sync, id}, _from, state) do 
    {data, state} = do_sync(id, state) 
    {:reply, data, state} 
end 

def handle_call({:sync_all, ids}, _from, state) do 
    {data, state} = Enum.map_reduce(ids, state, &do_sync/2) 
    {:reply, data, state} 
end 

defp do_sync(id, state) do 
    # do something 
    {data, new_state} 
end 
0

は多くの意味がありません、同じプロセスにGenServer呼び出しを行います。プロセスは、一度に1つのメッセージを処理します。コールが応答を待つ。ただし、プロセスは現在のメッセージで終了するまで応答できません。あなたが持っているコードは、プロセスが現在のメッセージの処理を終わらせることはないので、応答を待ってタイムアウトします。

一般に、キャストとコールを使用して、他のプロセスがメッセージをプロセスに送信するためのインターフェイスを定義します。実際のデータ変換を純粋な関数としてモデル化し、必要に応じてこれらを2つのハンドラ関数のそれぞれから呼び出すことができます。

関連する問題