Zapnuk
Zapnuk

Reputation: 655

How often/when does phoenix open static files?

we are currently developing our first single page application and noticed some unexpected behaviour when it comes to static files.

We set up our endpoint.ex by including our static files using Plug.Static:

plug Plug.Static,
    at: "/", from: :app,
    only: ~w(js index.html robots.txt)

Our router.ex includes the following routes:

scope "/", App do
    pipe_through :browser # Use the default browser stack
    get "/*path", PageController, :index
end

The PageController redirects to the static file:

@index "/index.html"

def index(conn, _params) do
   redirect(conn, to: @index)
end

We would expect the static files to be loaded once when the server starts. However when we used wrk to test (results below) the performance and noticed that requests to /index.html (the static resource) are only half as fast as requests to any other route that uses the redirect of the PageController.

./wrk -t4 -c200 -d30S --timeout 2000 "http://localhost:4000/index.html"
Running 30s test @ http://localhost:4000/index.html
  4 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
  Latency    46.39ms   31.24ms 443.14ms   95.68%
  Req/Sec     1.13k   264.38     1.49k    80.27%
134494 requests in 30.03s, 92.89MB read
   Socket errors: connect 0, read 30, write 0, timeout 0
Requests/sec:   4478.30
Transfer/sec:      3.09MB

./wrk -t4 -c200 -d30S --timeout 2000 "http://localhost:4000/anythingelse"
Running 30s test @ http://localhost:4000/indexjhtml
  4 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    30.88ms   49.61ms 760.40ms   94.79%
    Req/Sec     2.16k   679.55     4.58k    75.39%
256135 requests in 30.08s, 105.08MB read
Requests/sec:   8515.77
Transfer/sec:      3.49MB

We are wondering why the requests are slower accessing the static resource using the direct route compared to other paths that redirect to the static resource.

It seems like the static file get opened multiple times when we expect it to be opened just once.

Maybe someone could explain the static resources to us?

We also (sometimes) get a warning when doing the test for /index.html

13:59:00.247 [warn] Ranch acceptor reducing accept rate: out of file descriptors

Upvotes: 0

Views: 664

Answers (2)

Dogbert
Dogbert

Reputation: 222428

We are wondering why the requests are slower accessing the static resource using the direct route compared to other paths that redirect to the static resource.

This is because wrk does not follow the redirect. This can be verified by calculating the bytes per request from your stats.

/index.html: 134494 requests in 30.03s, 92.89MB read = ~724 bytes per request

/anythingelse: 256135 requests in 30.08s, 105.08MB read = ~430 bytes per request

So /anythingelse is smaller than /index.html according to wrk.

The 430 byte response is just the 302 redirect response written by phoenix for redirect(conn, to: "/index.html"). As you'd expect, just writing a 302 response is faster than reading and writing the contents of the file index.html.

It seems like the static file get opened multiple times when we expect it to be opened just once.

Files served by Plug.Static are not read and cached once; they're read from the disk on each request. If you want to store the contents in memory at compile time, you can read the file in your controller and then write it yourself in the action:

@index_html File.read!("path/to/index.html)

def index(conn, _params) do
  send_resp(conn, 200, @index_html)
end

Upvotes: 2

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121010

In development mode, phoenix makes it easy for you to develop applications by setting watch on the files for live reload. The setting is in config/dev.exs:

config :your_app, YourApp.Web.Endpoint,
  ...
  watchers: [node: ["node_modules/brunch/bin/brunch", "watch", "--stdin",
               cd: Path.expand("../assets", __DIR__)]]


# Watch static and templates for browser reloading.
config :your_app, YourApp.Web.Endpoint,
  live_reload: [
    patterns: [
      ~r{priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$},
      ~r{priv/gettext/.*(po)$},
      ~r{lib/your_app/web/views/.*(ex)$},
      ~r{lib/your_app/web/templates/.*(eex)$}
    ]
  ]

or similar. Tune this setting up to watch only what you want to be watched.

In both test and production environments this flag is obviously not set at all. It seems you also might want to make sure, that wrk runs in test environment.

Upvotes: -1

Related Questions