I compile and deploy my Phoenix projects manually, with no third-party library such distillery, and with a help of the commands “mix compile” and “mix release”, basically.
I need a way to run custom commands or tasks on a server in the production mode. It’d be similar to running migrations. But I’ve bewildered as for how it’s done. A project itself may or may not be up and running when a command or task is being executed. And I need to be able to pass some arguments to a said command-task.
How to do it?
I’m aware of
defmodule Mix.Tasks.MyTask1 do .... but how would I do it in production, on a server? Is this even a proper and recommended way to run them on a server in production?
I’m aware of bin/my_app eval 'MyProject.MyTask1' but why does it exist if there’s the other abovementioned approach? Again, is this one a proper and recommended way to run them on a server in production?
Are there other approaches?
I’m bewildered. Which one to use, in what circumstances? How to use them properly?
Your second option (/bin/app eval …) looks right. Mix is a build tool and is not a part of your release. There’s a nice example of how this can be done in the Phoenix “Deploying with releases” docs.
For passing arguments, you should be able to just pass them as arguments to the command you’re running — the mix release docs have the example of bin/RELEASE_NAME eval "IO.puts(:hello)".
I was trying to forward command-line arguments directly to my Elixir code being run. Doing it the naive way doesn’t work for arbitrary unexpected numbers of arguments and other reasons:
$ _build/prod/rel/my_app/bin/my_app eval "MyApp.Release.abc(\"$1\", \"$2\")" # this doesn't even properly escape double quotes, and ways to do that within bash are not consistent across systems
There is a supported way to forward the command line arguments though:
The command line arguments can then be accessed in your Elixir code using System.argv(). Hope this helps anyone facing the same problem. This seems like a better solution to me for anything more complex than passing hard-coded values from the shell script.