Hive
fix(server): ignore Mix compile lock in code reloader
GitHub issue · Closed
What changed
- Added
TuistWeb.CodeReloader, a small wrapper around Phoenix’s development code reloader. - Wired the dev endpoint’s
Phoenix.CodeReloaderplug to use the wrapper. - The wrapper normalizes Mix’s
_build/.../.mix/compile.lockmtime when that build artifact is the only stale “config” file. - The normalization now uses every configured reloadable app manifest, including path deps such as
:noora, not just the main:tuistmanifest. - Added focused regression tests for lock filtering, real config staleness, unrelated
compile.lockfiles, and multi-reloadable-app manifest mtimes.
Why it changed
Phoenix runs a stale-config guard before recompiling on each development request. With Elixir/Mix 1.19, Mix.Project.config_files() can include _build/.../.mix/compile.lock. That file is a build artifact, but if it is touched by an out-of-band Mix command while the server is alive, Phoenix treats it like config drift and returns the persistent “You must restart your server” 500 page.
The live repro also showed an extra wrinkle: Tuist reloads both :tuist and :noora in dev. Touching the lock back to the :tuist manifest was not enough if the lock was still newer than :noora’s manifest; Phoenix then failed while compiling noora.
Approach
The wrapper keeps Phoenix’s safety behavior for real config changes. Before delegating to Phoenix.CodeReloader.reload/2, it gathers manifests for all reloadable apps using the endpoint’s :reloadable_apps config and Mix.Dep.in_dependency/2 for path deps. If the only stale config entry is a Mix .mix/compile.lock, it touches that lock back to the oldest reloadable app manifest mtime. If any real config file is stale, the wrapper leaves everything alone and Phoenix still asks for a restart.
This keeps the fix local to Tuist’s development endpoint and avoids patching Phoenix internals.
Impact
Server preview sessions should stop getting wedged by Mix 1.19’s build lock artifact after local Mix commands touch compile.lock. Actual config changes remain restart-gated.
Validation
- Red regression: the new multi-manifest test failed before the fix because
compile.lockstayed newer than the simulatednooramanifest. MIX_ENV=test MIX_DEPS_PATH=/Users/marekfort/Developer/tuist/server/deps mise exec -- mix run --no-start -e 'ExUnit.start(); Code.require_file("test/tuist_web/code_reloader_test.exs"); %{failures: failures} = ExUnit.run(); System.halt(if failures == 0, do: 0, else: 1)'-> 6 tests, 0 failures.MIX_ENV=test MIX_DEPS_PATH=/Users/marekfort/Developer/tuist/server/deps mise exec -- mix format --check-formatted lib/tuist_web/code_reloader.ex test/tuist_web/code_reloader_test.exs lib/tuist_web/endpoint.ex.- Attempted the normal
MIX_TEST_PARTITION=_code_reloader MIX_DEPS_PATH=/Users/marekfort/Developer/tuist/server/deps mise exec -- mix test test/tuist_web/code_reloader_test.exs; it was blocked by local DB setup failing withrelation "users" does not existbefore ExUnit ran. - Live e2e: trusted the root and server mise configs, started the dev server with
MIX_DEPS_PATH=/Users/marekfort/Developer/tuist/server/deps mise exec -- mix phx.serveron the worktree port8501, and requestedGET /robots.txt. - Live e2e before widening the fix: after touching
_build/dev/lib/tuist/.mix/compile.lock, the request returned the stale-config 500:could not compile application: noora/You must restart your server. - Live e2e after the fix: baseline
GET /robots.txtreturned 503 because the local worktree DBtuist_development_421is missing; after touchingcompile.locknewer than bothnooraandtuistmanifests, the same request stayed at the baseline 503, the body did not contain the stale-config/restart message, andcompile.lockwas normalized older than both manifests.
No GitHub comments yet.