Skip to content

Instantly share code, notes, and snippets.

@sreecodeslayer
Last active August 28, 2019 10:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sreecodeslayer/e5983c6224bffc5387024c1ac771a392 to your computer and use it in GitHub Desktop.
Save sreecodeslayer/e5983c6224bffc5387024c1ac771a392 to your computer and use it in GitHub Desktop.
Fake Synchronous calls using Asynchronous GenServers in Elixir
defmodule MyAppWeb.AgentChannel do
use Phoenix.Channel
alias MyAppWeb.Endpoint
alias MyApp.AgentCommand
def push(topic, event, payload) do
Endpoint.broadcast("agent:#{topic}", event, payload)
end
def join("agent:" <> _topic, _message, socket) do
{:ok, socket}
end
@doc """
This is a handler for incoming messages on the "command_reply" topic from agents
"""
def handle_in("command_reply", payload, socket) do
AgentCommand.handle_reply(payload["command_ref"], payload["payload"])
{:noreply, socket}
end
end
defmodule MyApp.AgentCommand do
use GenServer
alias MyAppWeb.AgentChannel
alias MyApp.RandomStringGenerator
def start_link do
GenServer.start_link(__MODULE__, nil, name: __MODULE__)
end
@doc """
Call this function to send a command to agent
"""
def send(agent, command, command_payload, timeout \\ 20_000) do
payload = %{
command: command,
payload: command_payload
}
GenServer.call(__MODULE__, {:send, agent.topic, payload}, timeout)
end
@doc """
Call this function where the agent response is available
"""
def handle_reply(command_ref, reply) do
GenServer.cast(__MODULE__, {:handle_reply, command_ref, reply})
end
def init(_) do
{:ok, %{}}
end
def handle_call({:send, topic, payload}, from, state) do
{ref, state} = insert_with_unique_key(state, from)
payload = Map.put(payload, :command_ref, ref)
AgentChannel.push(topic, "command", payload)
{:noreply, state}
end
def handle_cast({:handle_reply, command_ref, reply}, state) do
{from, state} = Map.pop(state, command_ref)
GenServer.reply(from, reply)
{:noreply, state}
end
defp insert_with_unique_key(map, value) do
key = RandomStringGenerator.string_of_length(20)
if Map.has_key?(map, key) do
insert_with_unique_key(map, value)
else
{key, Map.put(map, key, value)}
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment