Random working directory in umbrella app

Hello everyone,

I am reading and writing some files using File.write!("tmp/random_file_name.txt") and File.read!("tmp/random_file_name.txt") from various points in my application, but they seem to randomly end up in, or being read from, the tmp folder in the umbrella root, or in the apps/my_app/tmp. There is no consistency in the behaviour on a per-module basis per instance. It seems that the current working directory is not always the directory that the app is started from.

The app is an umbrella app that contains a Phoenix project. It was migrated from a regular app into an umbrella, so maybe I’m missing some configuration. This is the project section of my app’s Mixfile:

  def project do
    [app: :my_app,
     version: "0.0.1",
     elixir: "~> 1.5.0",
     elixirc_paths: elixirc_paths(Mix.env),
     compilers: [:phoenix, :gettext] ++ Mix.compilers,
     build_embedded: Mix.env == :prod,
     start_permanent: Mix.env == :prod,
     aliases: aliases(),
     deps: deps(),
     build_path: "../../_build",
     deps_path: "../../deps",
     config_path: "../../config/config.exs",
     lockfile: "../../mix.lock",
     preferred_cli_env: [
        vcr: :test, "vcr.delete": :test, "vcr.check": :test, "vcr.show": :test
      ]
     ]
  end

This is the project section of the umbrella’s Mixfile:

  def project do
    [apps_path: "apps",
     build_embedded: Mix.env == :prod,
     start_permanent: Mix.env == :prod,
     deps: deps(),
     dialyzer: [ignore_warnings: ".dialyzer/ignore-warnings"],
     build_path: "_build",
     deps_path: "deps"]
  end

Any idea what might be going on here?

That should read and write from the working dir which was active when you started the app.

I would indeed expect so but it doesn’t seem to be. It will randomly alternate between the umbrella root and the app path.

When you run mix test in an umbrella project, it will go to the directory of each child application and run mix test inside that application. It should never be inside tmp though.

However hard coding paths in your application is generally not good. If you are reading contents that you need in production, then it should be placed in the priv directory. For other paths, you can always do the path relative to the current file by using __DIR__.

1 Like

I have been explicitly building the path to tmp directory by prepending it with full path to the root directory of my “web” application. In my case the full path to this root directory is:

MyApp.Web.Endpoint.config(:root)

If you have dependencies properly specified in your umbrella apps, this will return the same value no matter if ran this code from web/ core/ db/ or whatever other apps you have.

Note that you should only do it like that for dev and test environments. For production, you most likely want to specify some shared tmp directory that will survive deploys (maybe or maybe not), or put it to system /tmp/ directory somewhere. This is important because you may not have the mix application structure when you do a distillery release for example. It should be fine, however, if you deploy to heroku using Elixir/Phoenix buildpacks.

Thanks for the quick responses! I will try going down the route of configuring the path explicitly. We don’t really need these files in production which is why they were never in the priv directory in the first place but I will take the trade-offs into consideration. Thanks again!