2

I have mix task mix fetch.btc on phoenix app (lib/mix/tasks/fetch.btc.ex):

defmodule Mix.Tasks.Fetch.Btc do
  use Mix.Task

  def run(_args) do
    res = HTTPoison.get!("https://blockchain.info/ticker")
    IO.inspect(res)
  end
end

When I run mix fetch.btc I got error:

** (ArgumentError) argument error
    (stdlib) :ets.lookup_element(:hackney_config, :mod_metrics, 2)
    PROJ_DIR/deps/hackney/src/hackney_metrics.erl:27: :hackney_metrics.get_engine/0
    PROJ_DIR/deps/hackney/src/hackney_connect.erl:78: :hackney_connect.create_connection/5
    PROJ_DIR/deps/hackney/src/hackney_connect.erl:47: :hackney_connect.connect/5
    PROJ_DIR/deps/hackney/src/hackney.erl:330: :hackney.request/5
    lib/httpoison/base.ex:787: HTTPoison.Base.request/6
    lib/httpoison.ex:128: HTTPoison.request!/5
    lib/mix/tasks/fetch.btc.ex:14: Mix.Tasks.Fetch.Btc.run/1
    (mix) lib/mix/task.ex:331: Mix.Task.run_task/3
    (mix) lib/mix/cli.ex:79: Mix.CLI.run_task/2
    (elixir) lib/code.ex:767: Code.require_file/2

But in my controller this code res = HTTPoison.get!("https://blockchain.info/ticker") is work success!

Info:

hackney: 1.15.1
httpoison: 1.5.0
phoenix: 1.4.3
  1. What am I doing wrong?
  2. What is right way make http request in mix task?
Alexey Egorov
  • 2,221
  • 2
  • 18
  • 21

3 Answers3

4

The code in you controller runs when the application and all it’s dependencies are already started. mix tasks are run within :mix application which obviously does not start :hackney by default.

All you need is to ensure it’s started / start it manually:

def run(_args) do
  # ⇓⇓⇓⇓⇓⇓⇓ THIS ⇓⇓⇓⇓⇓⇓⇓
  Application.ensure_all_started(:hackney)
  # ⇑⇑⇑⇑⇑⇑⇑ THIS ⇑⇑⇑⇑⇑⇑⇑

  res = HTTPoison.get!("https://blockchain.info/ticker")
  IO.inspect(res)
end
Aleksei Matiushkin
  • 119,336
  • 10
  • 100
  • 160
  • thanks for you help! It's works! Where I can read more info about this for more understand? – Alexey Egorov May 02 '19 at 06:39
  • About OTP, supervision trees and how erlang virtual machine works? There are tons of resources all around the internets. I hesitate to suggest somewhat special, check the official list http://erlang.org/faq/obtaining.html – Aleksei Matiushkin May 02 '19 at 06:51
1

You can also use HTTPoison.start() before the actual call. That will also work, if you dont want to start the hackney application every time in mix file or if you do not want to start using Application.

Zubair Nabi
  • 1,016
  • 7
  • 28
  • what is realy happens when we call `HTTPoison.start()` ? – Alexey Egorov May 02 '19 at 06:51
  • `HTTPoison` is OSS, for God’s sake. https://github.com/edgurgel/httpoison/blob/master/lib/httpoison/base.ex#L216 – Aleksei Matiushkin May 02 '19 at 06:52
  • @ZubairNabi incorrect. Check the link I posted above: it starts not only required `:hackney` application, but the whole zoo. including `:httpoison` itself and all its dependencies. Well, dependencies are [`:hackney` only](https://github.com/edgurgel/httpoison/blob/master/mix.exs#L41), but still. – Aleksei Matiushkin May 02 '19 at 06:53
  • it actually does what @AlekseiMatiushkin did. Starts the Httpoison application and its dependencies. – Zubair Nabi May 02 '19 at 06:55
  • @AlekseiMatiushkin got it. yea, `Httpoison.start` starts all the application, however for the users specific problem he can start just 'hackney'. Thanks :+1 – Zubair Nabi May 02 '19 at 06:56
0

Add the following code to the file /test/test_helper.exs

# /test/test_helper.exs
ExUnit.start()
HTTPoison.start() # YOUR CODE HERE
Ecto.Adapters.SQL.Sandbox.mode(SocialNetworks.Repo, :manual)
Ruan Nawe
  • 363
  • 6
  • 9