newton-peixoto

newton-peixoto

Hello everyone I’m studying about http streams and I notice a big difference in performance when returning everything at once and when streaming and that made me think if streaming a big file is really worth it or if there is something wrong with my implementation (most likely that haha) So if anyone could help me understand this situation I’d appreciate a lot. Thanks

non-stream implementation

  get "/no-stream" do
    pokemons = File.read!("file.json")
    conn |> send_resp(200, pokemons)
  end

Stream implementation :

  get "/" do

    conn = conn
    |> put_resp_content_type("text/event-stream")
    |> put_resp_header("Access-Control-Allow-Origin", "*")
    |> send_chunked(200)

    File.stream!("file.json")
    |> Jaxon.Stream.from_enumerable
    |> Jaxon.Stream.query([:root, :all])
    |> Stream.map(fn element ->
     {:ok, pokemon}  = Jason.encode(element)
      conn |> chunk(pokemon <> "\n")
    end )
    |> Stream.run

    conn
  end

As you can see the stream implementation has a latency MUCH higher even though the memory peak is a little bit lower. The question here is trying to understand if this is normal or if I messed up somehow I understand if is not possible to achieve the same latency as File.read! but the difference here is so high that made me wonder if something if off

BTW: the lib used to run the load test is called hey

Showing Posts 1 to 4

D4no0

D4no0

Streaming is always slower than sending/processing the whole file at once. In this case I think the latency comes from the overhead of sending multiple http packets.

Usually you want to stream when the file can be very big, this will ensure that both the server will never run out of memory when loading the file in the memory and the client the same.

kwando

kwando

Looks like your streaming version does more work tbh, parsing and encoding JSON..

Also I believe send_file would be even faster :slight_smile:

newton-peixoto

newton-peixoto OP

changing the endpoint to

 File.stream!("file.json")
    |> Stream.map(fn line ->
      conn |> chunk(line)
    end )
    |> Stream.run

made the endpoint 99% response time to 3s way higher than the 0.3s from file.read! but as you mentioned faster than the current json encondig..

kip

kip

ex_cldr Core Team

When I think about when to stream I think of three cases:

  1. Time-to-first pixel is more important that absolute throughput. By streaming the user may be able to see something after the first chunk. In non-streaming the whole content has to arrive first. Very use case dependent.

  2. The content is being streamed from an external source (like S3) to Elixir and then transformed before sending to the HTTP client. In this case streaming may be more memory efficient and the stream-in/stream-out may manage the upstream latency and bandwidth better.

  3. The size of the content to be sent is non-trivial in terms of memory availability on the Elixir system. (as you’ve already pointed out).

I appreciate some of this may be more theoretical benefit rather than practical benefit so as always, testing and measuring is important.

— All posts loaded —

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
samoloth
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
FlyingNoodle
If a change or preparation module uses Ash.Changeset.get_argument/2 or Ash.Query.get_argument/2 (or any of the other get_argument functio...
New
ryanwinchester
apply_graft/2 doesn’t rewrite an add_many sub-workflow’s deps on an add step. Grafted jobs cancel with “upstream job was deleted” Version...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews