Phoenix livereload in vagrant / virtualbox

Cowboy 2.x allows disabling sendfile, which can be helpful for Vagrant environments with shared folders: https://github.com/ninenines/cowboy/commit/be09711687218070ee670be7d549df8338b4ae92

My question is fairly simple: given a Vagrant environment, and trying to start the Phoenix dev server via “iex -S mix phx.server”, how would I get Phoenix to pass the necessary switch to Cowboy to disable sendfile?

1 Like

in your config

   config :hello, HelloWeb.Endpoint,
      http: [ port: 4000, 
                 protocol_options: [sendfile: false] 
            ],...

Hm, still doesn’t seem to be working. Here’s what I’ve done:

  • Added protocol_options: [sendfile: false] to the http: section in config/dev.exs
  • Verify I’m running latest version of Cowboy with the sendfile fix (2.6.1)
  • Started the server with “iex -S mix phx.server”
  • Verify that webpack is properly compiling and watching the files
  • Edit a CSS file, and verify that the file has changed on the server

However, after saving the edited file, livereload doesn’t happen, and even refreshing the browser manually still loads the stale CSS file, so it appears that sendfile is not in fact disabled in Cowboy?

I’ve also verified that the config changes I made are passed in the Phoenix.Endpoint.init/2 callback, by tossing in a log statement there.

sounds like a bit of XY problem - where sendfile/cowboy isn’t the issue/solution…

is the css compiled by webpack - and if so can you post the webpack config - and also your “watchers” config perhaps?

perhaps also test your code(or minimal code project) outside of the vagrant environment to verify…

2 Likes

Both the webpack config and the “watchers” config were taken straight from the doc on upgrading to Phoenix 1.4: https://gist.github.com/chrismccord/bb1f8b136f5a9e4abc0bfc07b832257e#replace-brunch-with-webpack

Just did this by:

  • Copying the entire codebase to my OS X filesystem
  • mix deps.clean --all && mix deps.compiile
  • rm -rf assets/node_modules && cd assets && npm install && node node_modules/webpack/bin/webpack.js --mode development
  • iex -S mix phx.server

Live reload works perfectly in this instance, changing a CSS file is instantly updated in the browser.

This issue with Virtualbox and sendfile is well documented: https://www.virtualbox.org/ticket/9069 and several other issues, where the workaround in Nginx/Apache is to disable sendfile as a reasonable workaround for development.

With Cowboy 2.6.1 adding the ability to disable sendfile, my hope is that this issue can be addressed for Phoenix environments inside a Vagrant/Virtualbox VM, but all my efforts so far have not resulted in a working solution…

2 Likes

potentially it wont work (I see numerous issues on shared folders in vagrant/virtualbox), but do check https://github.com/phoenixframework/phoenix_live_reload#backends

I would first try with :fs_poll, and should that not work I would try and install inotify and see if that works…

edit: also check that you are on latest version of phoenix_live_reload…

I’ve got phoenix_live_reload 1.2.0 installed, which is latest.

Already have inotify-tools installed on the VM.

Also tried this:

config :phoenix_live_reload,
  backend: :fs_poll

Didn’t help.

The thing is, I have many Vagrant/Virtualbox installs, and don’t have this problem with any other stack besides Phoenix/Cowboy, using the sendfile fix for Nginx/Apache works perfectly.

This is why I suspect the entire issue is with getting Cowboy to properly implement that hack via Phoenix – the files in the shared folder on the VM themselves update fine, the issue is that the webserver serves up the stale file w/o the sendfile hack.

think the issue is way before cowboy serving the file (eg even webpack is not noticing the changed file, much less live_reload, and much less any cowboy issue - though that might be a secondary issue, once you get things going…)

config live_reload to fs_poll (as I read it inotify is not functional in vagrant…)

and try https://webpack.js.org/guides/development-vagrant/#running-the-server
eg run with --watch-poll instead of --watch-stdin…

there is also this one config possible https://www.javascriptstuff.com/webpack-watch-in-vagrant-docker/

watchOptions: {
  poll: true;
}

also it seems you can set poll to an integer eg poll: 500 - if the defaults polling uses too much cpu…

do keep us posted - and see about where a documentation/PR could be relevant if you are successful…

1 Like

OK, progress, you were correct about the webpack files, hadn’t occurred to me that’s a separate watch-ing system…

Added the following to my Webpack config, and now live reloading is working well for assets managed by Webpack:

watchOptions: {
  aggregateTimeout: 300,
  poll: 500,
  ignored: [
    'node_modules',
  ],
},

The instructions at https://webpack.js.org/guides/development-vagrant/#running-the-server indicated a need for --host and --public args to be passed to webpack-dev-server, but I didn’t find these necessary.

Live reloading isn’t working for the Elixir files yet, here’s my live reload config in config/dev.exs:

config :poof, PoofWeb.Endpoint,
  live_reload: [
    backend: :fs_poll,
    patterns: [
      ~r{priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$},
      ~r{priv/gettext/.*(po)$},
      ~r{lib/poof_web/views/.*(ex)$},
      ~r{lib/poof_web/templates/.*(eex)$},
    ],
  ]

Those pattern entries were generated when I created the Phoenix project, they seem correct, assuming the “.*(ex)$” and the like search those directories recursively?

Thankfully, changes to the Elixir files appear when I manually refresh the browser, so at least I’m to a point where I don’t have to restart the Phoenix dev server every time I make file changes!

Would be nice to get live reload for the Elixir files too, not sure what other steps I can take though…

1 Like

:clap: yeah for progress…

pretty sure the :fs_pool config is a global config like this: (and not as you have it)

config :phoenix_live_reload,
  backend: :fs_poll

see the readme https://github.com/phoenixframework/phoenix_live_reload#backends

I would keep an eye out for the “Polling file changes every #{interval}ms…” that should appear in the log on starting the server… https://github.com/falood/file_system/blob/master/lib/file_system/backends/fs_poll.ex#L42

facepalms…why don’t computers do what I mean instead of what I say?? :stuck_out_tongue:

OK, so moving the config there does get live reload working for Elixir files, however, it is dog slow – like 15-20 seconds between when I save the file and the live reload kicks in. Worse yet, it makes the loading of the Webpack managed files dog slow as well :frowning:

If I leave out the :fs_poll backend, the Webpack managed files are live reloading quite snappily, and the Elixir files don’t live reload at all.

I dug into the Filesystem app (which Phoenix Live Reload uses for doing its file watching magic), and I see this in the instructions: https://github.com/falood/file_system/blob/v0.2.6/lib/file_system.ex#L5-L18

Then the fs_poll backend has these additional options: https://github.com/falood/file_system/blob/v0.2.6/lib/file_system/backends/fs_poll.ex#L8-L10

However, setting the interval option like so:

config :phoenix_live_reload,
  backend: :fs_poll,
  interval: 500

And I still get this in the logs when booting up my app: “Polling file changes every 1000ms…”

Also, phoenix_live_reload has this for the filesystem dep:

{:file_system, "~> 0.2.1 or ~> 0.3"},

And the filesystem app has a very weird release schedule: https://github.com/falood/file_system/releases – is the newest version 0.2.6, or 0.4.2? Seems like 0.2.6

All very odd…

OK, real progress!

Turns out there are several limitations in phoenix_live_reload that contribute to the issues reported in my last post.

Briefly, phoenix _live_reload hard codes most of the options passed to the FileSystem module, which is responsible for emitting file change events. Some of these hard-coded values can perform poorly, at least in the Vagrant/Virtualbox case, so I’ve created a pull request to allow more customization: https://github.com/phoenixframework/phoenix_live_reload/pull/90

If this PR gets committed, then it’s probably worth it to get some doc in place for “How to configure Phoenix for dev in Virtualbox” or somesuch…

3 Likes

That doesn’t seem to be causing any issues, 0.2.6 is the most recent. It looks like the library was renamed from exfswatch to file_system and that’s when the version shift occurred: https://github.com/falood/file_system/commit/39038ee88f1d777f0ce95ec12766219a6800cca1 but the hex releases look normal: https://hex.pm/packages/file_system

But judging on your last post it looks like your down to the root of the issue! I’m glad that you’re making progress :slight_smile:

With the commit of https://github.com/phoenixframework/phoenix_live_reload/pull/90 this issue can be put to bed.

I did re-test the Cowboy 2.6 disabling of sendfile, and it turns out it’s not necessary with the webpack/phoenix_live_reload configuration – which makes sense since Cowboy isn’t directly serving any files in this case.

The one remaining thing would be to write up some user help for Vagrant/Virtualbox situations with live reload. I’d like to wait until phoenix_live_reload makes its next point release.

Where would be the best place to add the user help once that happens?

2 Likes

:clap: great work with the PR… and seems like you nailed the root issue(pun intended) of fs_polling 100k files or whatever there is in a root dir…

believe the webpack polling config is relevant to be documented somewhere? - perhaps that belongs in the phoenix docs - and then a note in the phoenix_live_reload readme linking to the phoenix docs or something… (or just a note in the phoenix_live_reload readme…)

maybe also change the topic of this discussion to “phoenix livereload in vagrant” or similar so it shows up in search results…

1 Like

I’d edit the post title, but I don’t see any way for me to do it, is it a permissions thing or am I missing something?

I believe the Webpack polling config should be documented somewhere, not sure where. I guess it depends if all of these Vagrant/Virtualbox related issues are relevant to only this use case or similar VM setups – in that case I’d advocate for a separate “Setting up Phoenix in Vagrant/Virtualbox” page or somesuch…