2017-03-21 15 views
3

와 GenServer를 다시 시작합니다비약 :이 전 <code>GenServer</code> 인스턴스가 있다고 가정 해 봅시다 특정 행동

defmodule MyModule do 
    use GenServer 

    def init(_) do 
    {:ok, %{}} 
    end 

#... 
end 

내가 감독 인 MyModule을 원하지만 충돌 때 충돌 이전 상태로 다시 시작하기 전에, 뭔가를 할 :

defmodule MyModule do 
    use GenServer 

    def init(_) do 
    {:ok, %{}} 
    end 

def init(:restart, previous_state) do 
    some_func(previous_state) 
    {:ok, previous_state} 
end 

#... 
end 

그러나 이것을 구현하는 방법을 모르겠다.

+0

이전 상태가 자동으로 다시 시작됩니다. – Dogbert

+0

그 상태로 무엇을하고 싶습니까? 로깅과 별개로 동일한 genserver가 재사용하는 유스 케이스를 상상할 수는 없습니다. 이전 상태로 인해 충돌이 발생했습니다. 비슷한 메시지가 나타나면 즉시 다시 충돌하지 않겠습니까? 크래시가 관리자에게 오류 메시지를 보냅니다. 당신은 아마 그것을 잡을 수 있고 그것으로 무언가를 할 수 있습니다. 그렇지 않으면 Dogbert가 제안한 방법을 사용하여 상태를 어딘가에 저장하고 다시 시작할 때 genserver가 상태를로드하게 만듭니다. – Johannes

+0

@Johannes 내 경우에는 상태가 크래시 자체를 유발할 수 있다고 말하고 싶지만이 상태에 유효한 호출을 적용하지 않으면 예외가 발생합니다. –

답변

1

나는 이것이 Dave Thomas의 저서에 설명되어 있음을 기억한다. 아이디어는 국가의 복제본을 유지하는 또 다른 프로세스를 갖는 것입니다. 이 프로세스에는 하나의 작업이 있습니다. 상태 변경을 추적합니다. 이렇게하면 충돌을 방지해야합니다 (원래 프로세스가 상태 변경에 대해 관찰자에게 알리는 경우 변경 사항을 적용하는 동안 크래시가 발생하지 않았 음을 의미합니다).

그러면 원래 프로세스가 충돌하고 다시 시작될 때 백업 프로세스에서 이전 상태를 가져올 수 있습니다 (해당 프로세스의 PID가 감독자에게 주어짐).

def start_link(backup_pid) do 
    GenServer.start_link(__MODULE__, backup_pid) 
end 

def init(backup_pid) do 
    state = Backup.get_state(backup_pid) 
    {:ok, state} 
end 

def terminate(_reason, state) do 
    Backup.save_state(state) 
end 
당신은`사용/2` 콜백을 종료하고 다른 곳에 상태를 저장 (에이전트, 데이터베이스, ETS) 및/init을 1`하지만 난 당신이 상사가 통과 할 수 있다고 생각하지 않습니다`에로드 할 수