I'm just starting out in Elixir and wanted to build a very simple API with Plug. I used this guide to get a very simple API up and running.
Basically, the problem I'm facing is that the process that I registered as :qs
doesn't seem to be found (and errors out), whenever I use the send/2
function in queue_service.ex
. What I'm trying to achieve is a process that sticks around so that I can have state being maintained across requests.
In my router.ex
file, I have:
defmodule SecondQueue.Router do
use Plug.Router
alias SecondQueue.Plug.VerifyParams
alias SecondQueue.QueueService
plug Plug.Parsers, parsers: [:urlencoded, :multipart]
plug :match
plug :dispatch
get "/receive-message" do
# gather query parameters from connection
queue = Map.get(conn.params, "queue")
message = Map.get(conn.params, "message")
# handle the params
QueueService.handle_incoming(queue, message)
send_resp(conn, 201, "Created")
end
end
Then inside queue_service.ex
, I initiate the queues process, register it to an atom of :qs
, and then want to be able to get at that process later via a function that a request calls. I have:
defmodule SecondQueue.QueueService do
alias SecondQueue.QueueStore
use Agent
{:ok, agent_pid} = QueueStore.start_queues_link()
Process.register(agent_pid, :qs)
def handle_incoming(queue, message) do
queue_atom = String.to_atom(queue)
send(:qs, {:put, queue_atom, "success"})
end
end
And then finally, in queue_store.ex
, I actually define the process that I want to store the state, and run a loop so that it stays alive, and ready to receive messages. I have:
defmodule SecondQueue.QueueStore do
def start_queues_link() do
Task.start_link(fn -> queues_loop(%{}) end)
end
defp queues_loop(map) do
receive do
{:get, key, caller} ->
send caller, Map.get(map, key)
queues_loop(map)
{:put, key, value} ->
IO.puts("i am here")
queues_loop(Map.put(map, key, value))
end
end
end
Update:
Github repo: https://github.com/qarthandgi/test-second-queue
Elixir is a compiled language. The code below gets executed during compilation stage; no process is being started in runtime.
defmodule SecondQueue.QueueService do
...
{:ok, agent_pid} = QueueStore.start_queues_link()
Process.register(agent_pid, :qs)
...
end
Instead, you need to put this code into a function and explicitly call this function to start QueueStore
(directly or by plugging it into your app’s supervision tree.)