現在、ナディア、fsm、Exactorを使用してチャットボットを構築中です。私はすべてのユーザーの会話を有限状態マシンとしてモデル化して、各ユーザーが現在いる各状態の参照を持ち、キャッシュを使用して、ユーザーのチャットIDと使用しているfsmの対応するPIDを参照しようとしています。エリクサーfsmとエキスパクターが反応するまでに時間がかかります
次のスニペットに私のデザインは、それは私が使用して可能性のあるイベントを作成する(ポーリング)
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
次の状態に移行しようとしたときに立ち往生pidを作成しますが、ベース次のコードfsm library's github page
@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
に見出され、この特定の例のために、これは、Tである例に基づいて私は
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"}
を使用した例である私はせずにそれを呼び出す場合は、FSMデータ構造体は、それ自体で動作しますFsmServerを利用しています。
この大規模な遅延の原因は何ですか? さらに、FSMの複数のインスタンスを同時にどのように管理できますか?
のような関数を作成することは、[デッドロック]のように見える、genserverの内側genserverを呼んでいました://en.wikipedia.org/wiki/Deadlock)。 'start_polling'は何をしますか?あなたはこのモジュールの完全なコードを投稿できますか? – Dogbert
私はいくつかの情報でこれを更新し、FsmServerモジュールとFsmデータ構造のこのhastebinを追加しました。 https://hastebin.com/simetibave.sql – user2070502
私はExActorを使ったことがないので、構文はわかりませんが、この問題は通常、別の 'call'または' cast'の中からGenServer 'call'を作ると起こります'。一度に1つのメッセージしか処理されないので、2番目の呼び出しは現在の呼び出しが終了する前に実行されず、結果としてタイムアウトになります。 – Dogbert