New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

starting server with mix phoenix.server not reloading server side code #1165

Closed
christopherslee opened this Issue Aug 29, 2015 · 18 comments

Comments

Projects
None yet
@christopherslee

christopherslee commented Aug 29, 2015

Hi,

hate to ask this question for fear of making a newbie mistake.

I uninstall all versions of elixir I had from brew, and reinstalled elixir 1.0.5.

> brew list elixir
/usr/local/Cellar/elixir/1.0.5/bin/elixir
/usr/local/Cellar/elixir/1.0.5/bin/elixirc
/usr/local/Cellar/elixir/1.0.5/bin/iex
/usr/local/Cellar/elixir/1.0.5/bin/mix
/usr/local/Cellar/elixir/1.0.5/lib/eex/ (7 files)
/usr/local/Cellar/elixir/1.0.5/lib/elixir/ (200 files)
/usr/local/Cellar/elixir/1.0.5/lib/ex_unit/ (21 files)
/usr/local/Cellar/elixir/1.0.5/lib/iex/ (13 files)
/usr/local/Cellar/elixir/1.0.5/lib/logger/ (10 files)
/usr/local/Cellar/elixir/1.0.5/lib/mix/ (71 files)

I have phoenix 1.0.0 with a newly generated project following the tutorial:

> mix deps
* fs 0.9.1 (Hex package)
  locked at 0.9.2 (fs)
  ok
* ranch 1.1.0 (Hex package)
  locked at 1.1.0 (ranch)
  ok
* poolboy 1.5.1 (Hex package)
  locked at 1.5.1 (poolboy)
  ok
* decimal 1.1.0 (Hex package)
  locked at 1.1.0 (decimal)
  ok
* poison 1.5.0 (Hex package)
  locked at 1.5.0 (poison)
  ok
* cowlib 1.0.1 (Hex package)
  locked at 1.0.1 (cowlib)
  ok
* cowboy 1.0.2 (Hex package)
  locked at 1.0.2 (cowboy)
  ok
* plug 1.0.0 (Hex package)
  locked at 1.0.0 (plug)
  ok
* phoenix_html 2.1.2 (Hex package)
  locked at 2.1.2 (phoenix_html)
  ok
* phoenix 1.0.0 (Hex package)
  locked at 1.0.0 (phoenix)
  ok
* phoenix_live_reload 1.0.0 (Hex package)
  locked at 1.0.0 (phoenix_live_reload)
  ok
* postgrex 0.9.1 (Hex package)
  locked at 0.9.1 (postgrex)
  ok
* ecto 1.0.0 (Hex package)
  locked at 1.0.0 (ecto)
  ok
* phoenix_ecto 1.1.0 (Hex package)
  locked at 1.1.0 (phoenix_ecto)
  ok

I am on OS X 10.9.5

When I change any code in web, the server does not recompile the code, and I have to restart the server for changes to take effect. For example, if I change the HelloController from the tutorial.

However, when I make changes to templates, those changes are picked up at the livereload works as designed.

I did not make any modifications to my dev.exs, and code_reloader: true is set.

Did I miss a step somewhere? I did my best to google/github search for similar issues.

[edit]
continued googling and looking at the FS dependency, i found this issue from josevalim:
synrc/fs#17 which links to #920

Is there a workaround for os x yet? or is this a common issue?

Thanks!
Chris

@chrismccord

This comment has been minimized.

Member

chrismccord commented Aug 29, 2015

Let's start simple. What editor are you using? Are you using a plugin like syntactic in vim that check for syntax errors? These have been known to cause issues because they mess with ctime/mtime. Can you try a different editor really quickly, i.e. open a controller in TextEdit, save it, then refresh. If you still don't see a recompile, we'll keep digging.

@christopherslee

This comment has been minimized.

christopherslee commented Aug 29, 2015

wow, thanks @chrismccord. you nailed it.

i was using vim, and if i switched to atom or something else, it worked fine.

i'm guessing this is a known issue with no other workaround at this time but to disable the plugin?

@chrismccord

This comment has been minimized.

Member

chrismccord commented Aug 29, 2015

i'm guessing this is a known issue with no other workaround at this time but to disable the plugin?

yes, unfortunately. What happens is the plugin saves and recompiles the file behind the scenes, so when the next browser request comes in, mix looks at the project and all files are already compiled, and it noops. I'm not aware of any workarounds, so if you aren't married to the plugin, I'd disable.

@christopherslee

This comment has been minimized.

christopherslee commented Aug 29, 2015

thanks for the explanation and the help.

@danhper

This comment has been minimized.

Contributor

danhper commented Nov 11, 2015

Hi,
I had the same issue with Atom linter, which also recompiles the project in the background.
I thought a simple workaround would be to tell the linter to touch the file after it is done,
so that when the next request comes, the reloader compiles the changes.
After giving it a shot, it seems that touching the file just after the project has been recompiled does not have any effect. I had to set the modification timestamp about 800ms after the recompilation for the code reloading to happen.
Is there some threshold value in mtime difference for the files to be recompiled, or is there some other explanation?
Thanks!

@chrismccord

This comment has been minimized.

Member

chrismccord commented Nov 11, 2015

Is there some threshold value in mtime difference for the files to be recompiled, or is there some other explanation?

No. The explanation sounds like you are racing the code reloading detecting the changes, issues a new request, and recompiling the project.

@danhper

This comment has been minimized.

Contributor

danhper commented Nov 11, 2015

@chrismccord Thanks for the quick reply, I am going to try to find a better workaround.

@bigardone

This comment has been minimized.

bigardone commented Dec 1, 2015

Hi @tuvistavie ! Have you finally found a better workaround? I'm experiencing just the same issue with Atom.io and linter-elixirc :(
Thanks in advance!

@danhper

This comment has been minimized.

Contributor

danhper commented Dec 2, 2015

Hi @bigardone, I am still using my clumsy timestamp hack, it's not perfect but still much better than working without linter or without code reload for me.

@bigardone

This comment has been minimized.

bigardone commented Dec 2, 2015

@tuvistavie thanks for the response. I've found that checking the 'Always use elixirc' option in the linter-elixirc package settings makes it work like a charm.

atom - settings

@danhper

This comment has been minimized.

Contributor

danhper commented Dec 3, 2015

@bigardone This works great, thanks!

@mollerhoj

This comment has been minimized.

mollerhoj commented Jul 28, 2016

Has anyone found a fix for vim/syntastic users?

@geowa4

This comment has been minimized.

geowa4 commented Aug 17, 2016

@mollerhoj this is what I use with Neomake, which I assume can translate to Syntastic.

let g:neomake_elixir_enabled_makers = ['elixir']
let g:neomake_elixir_elixir_maker = {
      \ 'exe': 'elixirc',
      \ 'args': [
        \ '--ignore-module-conflict', '--warnings-as-errors',
        \ '--app', 'mix', '--app', 'ex_unit',
        \ '-o', '$TMPDIR', '%:p'
      \ ],
      \ 'errorformat':
          \ '%E** %s %f:%l: %m,' .
          \ '%W%f:%l'
      \ }

If you look closely, I had to change the warning format for Elixir 1.3 from what's in the source (https://github.com/neomake/neomake/blob/ae6639b3cf6c263a54239648ce6522b569eaced7/autoload/neomake/makers/ft/elixir.vim#L11). This is not ideal, and I've opened elixir-lang/elixir#5143 to address it.

@akoutmos

This comment has been minimized.

akoutmos commented Jun 12, 2017

Thankfully I found this else I would have wasted way too much time debugging something that was working just fine. I figured I'd post my workaround in case it helps other people. I too use VIM, along with Ale for linting (https://github.com/w0rp/ale).

Ale provides a hook to execute an arbitrary function after linting is complete. What I did was disable Ale, sleep for a small amount of time, resave the file, and enable Ale again. Unfortunately I couldn't get it to work without the sleep...but then again i didn't invest a ton of time into this. Below 500ms it would work sometimes and fail other times. If someone can come up with a more elegant solution that would be awesome! Below are my .vimrc related to Ale:

" Settings for Ale
let g:ale_lint_on_text_changed = 'never'
let g:ale_sign_column_always = 1
let g:ale_statusline_format = ['⨉ %d', '⚠ %d', '⬥ ok']
let g:ale_javascript_eslint_executable = 'eslint_d'
let g:ale_sign_error = '✗'
let g:ale_sign_warning = '⚠'

augroup AleGroup
    autocmd!
    autocmd User ALELint call TouchOpenFile()
augroup END

func! TouchOpenFile()
    let g:ale_enabled = 0
    sleep 500m
    w                                                 
    let g:ale_enabled = 1
endfunc

dsdshcym added a commit to dsdshcym/.emacs.d that referenced this issue Oct 17, 2017

elixir: stop using flycheck-mix
- it's conflicting with phoenix code reloading
- see phoenixframework/phoenix#1165
@foliolin

This comment has been minimized.

Contributor

foliolin commented Dec 11, 2017

Just stumble into this as a Vim Ale user. After testing, I found that the reason reloading isn't working is that when a mix task doesn't exist, mix would compile the current source then complain about the missing task.

Step to replicate this behaviour:

cd /tmp
mix phx.new hello
cd hello
mix compile
mix dogma # Since it's compiled in the previous step, you won't see a compile message, you'll just see a complaint
echo '' >> lib/hello_web/controllers/page_controller.ex
mix dogma # Since the source was modified in the previous, you'll see a compile message, and also the same complaint
# Now add `{:dogma, "~> 0.1", only: :dev},` to the mix.exs file
mix deps.get
mix compile
mix dogma # No compile message here of course
echo '' >> lib/hello_web/controllers/page_controller.ex
mix dogma # No compile message here again!!
mix compile # This proves that mix dogma stops compiling source if the task exists

Based on the knowledge that mix missing_task recompiles and that the default linters for ale for elixir are credo and dogma, we have a conclusion that if you don't have either credo or dogma, you're in a pickle.

So the simple workarounds here are:

  1. Add both credo and dogma to deps or
  2. Don't install mix on your machine and start your projext in a docker container or (here is how you do it: https://github.com/sharils/Dockerfile/tree/master/phoenix )
  3. Delete all linters from ale/ale_linters/elixir/ directory

However, I believe the ultimate solution would be looking into the mix command and see if it's possible to not recompile if the task is not found. Since this is a problem that's gonna exist in all editors.

bzf added a commit to bzf/dotfiles that referenced this issue Jan 10, 2018

bzf added a commit to bzf/dotfiles that referenced this issue Jan 10, 2018

rafaelrinaldi added a commit to rafaelrinaldi/ale that referenced this issue Jan 20, 2018

kevinkjt2000 added a commit to kevinkjt2000/dot-vim that referenced this issue May 13, 2018

@amituuush

This comment has been minimized.

amituuush commented Nov 4, 2018

I had a vs-code-elixir-linter package installed in VSCode that caused this. Just disabling or uninstalling fixed the issue 👍🏼

@ellispritchard

This comment has been minimized.

ellispritchard commented Nov 8, 2018

I had this problem with VSCode's elixir language server... the problem is that the files get recompiled by the external editor, but not re-loaded by the code-reloader module in the running Erlang VM, because the compiler does nothing when everything looks up-to-date.

I while back I extended a module someone designed for non-Phoenix use, which is based on the built-in Phoenix.CodeReloader, to take into account the modification time of the build manifest files, and checks if they have changed since the last request; this then works with external compilations made by editor modules and other tools, and could be folded back into Phoenix.

See the fork here: https://github.com/Financial-Times/code_reloader, in particular the https://github.com/Financial-Times/code_reloader/blob/master/lib/code_reloader/server.ex mix_compile_unless_stale_config/2 and reload_modules/0.

The main change is that if the manifests are found to have been modified on the file-system since the last check, then after forcing a compilation (which may do nothing), the :code module is used to purge and load all modified modules (where modified means "the in-memory version isn't the same as the filesystem version").

@OvermindDL1

This comment has been minimized.

Contributor

OvermindDL1 commented Nov 8, 2018

A quick fix is just making the vscode/atom/whatever elixir language server use MIX_ENV=test instead of the default dev too. Though it would be very nice to fix the code reloader.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment