我目前正在使用Nadia,fsm和Exactor构建聊天机器人。我试图将每个用户对话建模为有限状态机,以便参考每个用户当前所处的每个状态,并使用缓存在用户聊天ID和其对应的fsm之间进行参考。 ;重新使用。
我的设计基于this tutorial
以下代码段会创建pid,但每当我尝试转换到下一个状态(轮询)时它就会卡住
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
上的示例使用以下代码创建可能的事件
@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
对于这个特殊的例子,这是我正在调用
的事件 defstate start do
defevent start_polling(id) do
next_state(:polling, get_user_info(id))
end
end
但get_user_info函数不会导致速度减慢 这是使用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"}
如果我在不使用FsmServer的情况下调用它,FSM数据结构就可以自行运行。
可能导致这种大规模滞后的原因是什么? 或者更好的是,我如何同时管理多个FSM实例?
答案 0 :(得分:1)
我在genserver里面调用了genserver,所以它最终出现在Doglock建议的死锁中,为了解决这个问题,我修改了start_link并创建了这样的函数
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