I'm using Elixir/Phoenix and I have an endpoint that returns a chunked response like say a never ending stream of log lines. The log lines, however, come from another service A which also returns a chunked response. I want my endpoint to read the chunked response from service A and pass them through to the client also in chunks. In essence, it's just a proxy for service A, but I can't let the client connect directly to service A because I need to perform some authentication.
Asked
Active
Viewed 2,329 times
3

Afshin Moazami
- 2,092
- 5
- 33
- 55

Jesse Shieh
- 4,660
- 5
- 34
- 49
-
You should use any HTTP client and make authentication on your own. The only issue I see here is the size of chunked data, but propably using Stream / Flow might help. – PatNowak May 15 '17 at 05:37
1 Answers
8
Here's an example of sending chunk data with Phoenix:
def test_1(conn, _params) do
conn = conn
|> put_resp_content_type("text/event-stream")
|> send_chunked(200)
conn |> chunk("a")
conn |> chunk("b")
conn |> chunk("c")
# send data five times, once per second, to simulate a log
for n <- 1..5 do
conn |> chunk(Integer.to_string(n))
Process.sleep(1000)
end
conn
end
There are a few http libraries available for Elixir/Erlang; I like HTTPoison
.
Here is an example that reads chunks from a url, and sends them off as they come in:
def test_2(conn, _params) do
url = "http://localhost:4000/test_1"
%HTTPoison.AsyncResponse{id: id} = HTTPoison.get!(url, %{}, stream_to: self())
conn = conn
|> put_resp_content_type("text/event-stream")
|> send_chunked(200)
process_httpoison_chunks(conn, id)
end
def process_httpoison_chunks(conn, id) do
receive do
%HTTPoison.AsyncStatus{id: ^id} ->
# TODO handle status
process_httpoison_chunks(conn, id)
%HTTPoison.AsyncHeaders{id: ^id, headers: %{"Connection" => "keep-alive"}} ->
# TODO handle headers
process_httpoison_chunks(conn, id)
%HTTPoison.AsyncChunk{id: ^id, chunk: chunk_data} ->
conn |> chunk(chunk_data)
process_httpoison_chunks(conn, id)
%HTTPoison.AsyncEnd{id: ^id} ->
conn
end
end
Some references:

stoodfarback
- 1,299
- 9
- 12
-
-
2I just implemented this, but noticed that the connection is dropped when I don't receive another chunk for 5 seconds or so. Do you happen to know of a way to keep the tcp connection alive? – Jesse Shieh May 18 '17 at 21:56
-
2@JesseShieh Ah, yep, there's a `recv_timeout` option for `HTTPoison` which defaults to `5000`ms. You can set it to something large, or `:infinity`. Something like: `HTTPoison.get!(url, %{}, stream_to: self(), recv_timeout: :infinity)` – stoodfarback May 19 '17 at 00:08
-
1`recv_timeout: :infinity` is quite dangerous usually. Better to set the timeout to something long and let it fail eventually. – Jason G May 20 '17 at 02:26