Hive Hive
Sign in

fix(server): ignore Mix compile lock in code reloader

GitHub issue · Closed

Metadata
Source
tuist/tuist #11396
Updated
Jun 24, 2026
Details

What changed

  • Added TuistWeb.CodeReloader, a small wrapper around Phoenix’s development code reloader.
  • Wired the dev endpoint’s Phoenix.CodeReloader plug to use the wrapper.
  • The wrapper normalizes Mix’s _build/.../.mix/compile.lock mtime 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 :tuist manifest.
  • Added focused regression tests for lock filtering, real config staleness, unrelated compile.lock files, 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.lock stayed newer than the simulated noora manifest.
  • 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 with relation "users" does not exist before 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.server on the worktree port 8501, and requested GET /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.txt returned 503 because the local worktree DB tuist_development_421 is missing; after touching compile.lock newer than both noora and tuist manifests, the same request stayed at the baseline 503, the body did not contain the stale-config/restart message, and compile.lock was normalized older than both manifests.
Comments

No GitHub comments yet.