One big issue: by default, GenServer.call has a timeout of 5 seconds. HTTPoison.get has a timeout of 8 seconds.
If a request to one of these services takes longer than 5 seconds, the Plug worker that sent the fetch request will time out and crash (your first example). But the fetcher will keep running.
If a request to one of these services takes more than 8 seconds, HTTPoison.get will return {:error, %HTTPoison.Error{reason: :timeout}} and the fetcher will cache that value for 30 seconds.
During that 30 seconds, further calls to that fetcher will return that same :error tuple immediately and crash in gas_station.ex’s handlers since they match on {:ok, gas_info} (your second example).
There’s also a hidden bug in those fetchers - if they ever get a non-200 HTTP status in a reply, they will still try to decode the body (and probably crash).
Some suggestions:
adjust the code in GasStation.Fetchers.GasServer.get to give GenServer.call a longer timeout, since a “normal” request could take up to 8 seconds
adjust the code in the fetchers to be smarter about handling errors - should timeouts be cached? Would it be better to cache the “last valid data”? What should happen if HTTPoison connects successfully but gets an HTTP error?
adjust the code in the router to not assume {:ok, gas_info} responses