Sam Houston
Sam Houston

Reputation: 3661

Start node process in elixir then return result of a http request

Using Porcelain and HTTPoison I would like to do the following:

I have been trying something like the following:

require HTTPoison
alias Porcelain.Process, as: Proc
alias Porcelain.Result, as: Res


def request do
  cmd = "node node_app/src/index.js"
  opts = [out: {:send, self()}]
  proc = %Proc{pid: pid} = Porcelain.spawn_shell(cmd, opts)

  receive do
    {^pid, :data, :out, log} ->
      IO.puts "Node log => #{log}"
      # only if log contains "running" should I send the request
      if String.contains?(log, "running") do
        IO.puts "Requesting..."
        %HTTPoison.Response{body: body} = HTTPoison.get! @root_url <> "/collection"
        Proc.stop(proc)
      end
    {^pid, :result, %Res{status: status} = res} ->
      nil
  end

  Proc.await proc # wait for the process to terminate
  body # return body of request
end

One problem is that I don't have control over when I can return out of the receive.

I get an elixir warning that body may not be defined which I would like to avoid.

Am I going about this the wrong way? Is there a nicer way to be doing this?

Thanks in advance for the help

Upvotes: 0

Views: 236

Answers (1)

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121010

There are two glitches with this code: first of all, one should stop the spawned process in any case.

Secondary, you should bind the whole result of receive to the variable. Something like this should work (untested):

result = receive do
  {^pid, :data, :out, log} ->
    IO.puts "Node log => #{log}"
    # only if log contains "running" should I send the request
    if String.contains?(log, "running") do
      IO.puts "Requesting..."
      HTTPoison.get! @root_url <> "/collection"
    end
  {^pid, :result, %Res{status: status} = res} ->
    nil
end

Proc.stop(proc)

with %HTTPoison.Response{body: body} <- result, do: body

The last Kernel.SpecialForms.with/1 will effectively return anything that did not match the expected Response, or body if match succeeded.


Sidenote: the warning is indeed a future runtime error. body was defined in the scope of receive, which makes it invisible to the closing scope.

Upvotes: 1

Related Questions