2017-10-16 5 views
0

Ich baue gerade einen Chatbot mit Nadia, FMS und Exactor. Ich versuche, jede Benutzerkonversation als eine endliche Zustandsmaschine zu modellieren, um einen Bezug auf jeden Zustand zu haben, in dem sich jeder Benutzer gerade befindet, und einen Cache zu verwenden, um einen Bezug zwischen der Benutzer-Chat-ID und der entsprechenden pid der verwendeten fsm zu haben.Elixir fsm und Exactor braucht ewig zu reagieren

I basiert mein Design auf this tutorial

folgenden Ausschnitt der pid schafft, aber es stecken bleibt, wenn ich versuche, in den nächsten Zustand (Polling)

defp create(id) do 
    {:ok, pid} = start_link() 
    Cache.get_or_create(:teleid2pid, id, pid) 
    IO.inspect "Changing to polling" 
    start_polling(pid, id) 
    pid 
end 

def pid_or_create(id) do 
    pid = Cache.get_value(:teleid2pid, id) 
    case pid do 
    nil -> create(id) 
    _ -> pid 
    end 
end 

Ich schaffe die möglichen Ereignisse für den Übergang der Verwendung folgender Code basierend auf dem Beispiel auf den fsm library's github page

gefunden
@one_arity_events [:start_polling, :edit_info, :update_db] 
    for event <- @one_arity_events do 
    defcall unquote(event)(data), state: fsm do 
     FlowFsm.unquote(event)(fsm, data) 
     |> new_state 
    end 
    end 

Und für dieses Beispiel ist dies t er Fall, dass ich

defstate start do 
    defevent start_polling(id) do 
    next_state(:polling, get_user_info(id)) 
    end 
end 

Aufruf Aber die get_user_info Funktion verursacht nicht die Verlangsamung Dies ist ein Beispiel unter Verwendung von iEx

iex(1)> alias TelegramBot.FsmServer 
    TelegramBot.FsmServer 
    iex(2)> alias TelegramBot.FlowFsm 
    TelegramBot.FlowFsm 
    iex(3)> pid = FsmServer.pid_or_create("1") 
    [debug] QUERY OK source="users" db=2.7ms decode=2.6ms 
    "Changing to polling" 
    ** (exit) exited in: GenServer.call(#PID<0.334.0>, {:start_polling,"1"}, 5000) 
    ** (EXIT) time out 
(elixir) lib/gen_server.ex:774: GenServer.call/3 
(backend) 
lib/backend/telegram_chatbot/fsm/fsm_server.ex:19: 
TelegramBot.FsmServer.create/1 
iex(3)> pid = FsmServer.pid_or_create("1") 
#PID<0.334.0> 
iex(4)> FsmServer.state(pid) 
:polling 
iex(5)> FlowFsm.get_user_info("1")   
%{db_id: 1, telegram_id: "1"} 

Die FSM-Datenstruktur von selbst funktioniert, wenn ich es so nennen, ohne Nutzen Sie den FsmServer.

Was könnte diese massive Verzögerung verursachen? Oder noch besser, wie könnte ich mehrere Instanzen von FSM gleichzeitig verwalten?

+0

Sieht aus wie ein [Deadlock] (https : //en.wikipedia.org/wiki/Deadlock). Was macht 'start_polling'? Können Sie den kompletten Code dieses Moduls posten? – Dogbert

+0

Ich habe es gerade mit ein paar mehr Informationen aktualisiert und diese Eiltebin des FsmServer-Moduls und der Fsm-Datenstruktur hinzugefügt. https://hastebin.com/simetibave.sql – user2070502

+1

Ich habe noch nie verwendet EXACTOR so die Syntax mir fremd ist, aber dieses Problem in der Regel passiert, wenn Sie einen GenServer 'call' aus einem anderen' call' oder 'Besetzung machen '. Da nur eine Nachricht gleichzeitig verarbeitet wird, wird der zweite Aufruf nicht ausgeführt, bevor der aktuelle beendet wird, was zu einem Timeout führt. – Dogbert

Antwort

1

ich die genserver Innenseite des genserver Aufruf, so dass es in einem Deadlock endete als Dogbert, schlug dieses Problem zu beheben ich die START_LINK modifiziert und erstellen Funktion wie diese

defstart start_link(id), do: initial_state(create_fsm(id)) 

defp create(id) do 
    {:ok, pid} = start_link(id) 
    Cache.get_or_create(:teleid2pid, id, pid) 
    pid 
end 

defp create_fsm(id) do 
    FlowFsm.new 
    |> FlowFsm.start_polling(id) 
end