Search code examples
processelixirphoenix-frameworkerlang-supervisor

Improve service method with elixir Processes and Supervisors


I'm building a service that will be making requests to two external APIs. The results are persisted in the local database.

Roughly, the method should work like this:

def make_requests(conn, params) do
  case Service1.request(params) do
    {:ok, response1 } ->
      case Service2.request(params) do
        {:ok, response2 } -> 
          conn 
          |> Repo.insert(response1)
          |> Repo.insert(response2)
          |> render("show.json")
        {:error, message} -> 
          conn |> render("error.json")
      end
    {:error, message } -> 
      conn |> render("error.json")
  end
end

New to elixir, I've been reading about Processes and Supervisors. My question is: Does is make sense to use them here? Could I make the method faster, more performing, or maybe improve fault tolerance by implementing them here?


Solution

  • Since you asked specifically whether this could improve performance or fault tolerance, I think the answer if yes. You can use Task.async to perform the requests in parallel since it doesn't look like the requests depend on each other. Same for the database inserts. I would probably use a Task.Supervisor here. You can also configure it to retry in case of failure, just be careful not to end up with duplicates by ensuring the requests and database inserts are idempotent.

    For example,

    import Supervisor.Spec 
    
    children = [ 
      supervisor(Task.Supervisor, [[name: ExampleApp.TaskSupervisor, restart: :transient]]), 
    ] 
    
    {:ok, pid} = Supervisor.start_link(children, strategy: :one_for_one)
    

    Then,

    {:ok, pid} = Task.Supervisor.start_child(ExampleApp.TaskSupervisor, fn -> 
      {:ok, response} = Service1.request(params)
      Repo.insert(response)
    end)
    {:ok, pid} = Task.Supervisor.start_child(ExampleApp.TaskSupervisor, fn -> 
      {:ok, response} = Service2.request(params)
      Repo.insert(response)
    end)