The following will first show off using Phoenix with exrm and then try some ideas to improve usage.
Assumes a freshly generated Phoenix app called hello_phoenix
& the current working dir is the project’s root dir.
Add exrm as dependency in mix.exs
Fetch & compile deps
$ mix deps.get
$ mix deps.compile
As soon as you generate a Phoenix or any mix app, your app’s version in mix.exs
would be 0.0.1. To generate a release run the following:
$ mix release
You can now start the app with the following:
$ rel/hello_phoenix/bin/hello_phoenix start
To check if your application is running, ping
your application and it should return pong
.
$ rel/hello_phoenix/bin/hello_phoenix ping
pong
Apart from start
& ping
You can run other common tasks like:
stop
- stops the running appconsole
- to start the app with an IEx shellremote_console
- to connect to an already running app and start a shelland a few more.
To start a phoenix app normally, you would run mix phoenix.server
.
An exrm release does not come with any mix tasks. This means, like before, you cannot start the Phoenix server using the mix phoenix.server
mix task.
To workaround this, you can instruct Phoenix to start the server by default when the OTP app starts. This can be done by setting the server
option to true in your environment specific config. We’ll assume dev
env right now. So our config file would be config/dev.exs
.
Change the following:
config :hello_phoenix, HelloPhoenix.Endpoint,
http: [port: 4000],
debug_errors: true,
code_reloader: true,
cache_static_lookup: false,
watchers: [node: ["node_modules/brunch/bin/brunch", "watch"]]
to look like below:
config :hello_phoenix, HelloPhoenix.Endpoint,
http: [port: 4000],
debug_errors: true,
code_reloader: true,
cache_static_lookup: false,
watchers: [node: ["node_modules/brunch/bin/brunch", "watch"]],
server: true
Notice the extra server: true
option in the end?
Now lets blow up the release and create a new one. Ensure your release is stopped and then run the following to destroy everything about releases in your app.
$ mix release.clean --implode --no-confirm
Create another release and start the release. Your app should now be accessible at localhost:4000
as usual.
Instead of stopping & starting apps everytime you want to deploy. Your flow would be the following if you used hot code-reloading.
Whenever the app is updated, this would be the workflow:
project
function mix.exs
mix release
Assuming there’s a release already running for version 0.0.1
of the app & the next version of the app is 0.0.2
, as mentioned in mix.exs
, you would do the following:
$ SERVER=1 mix release
$ rel/hello_phoenix/bin/hello_phoenix upgrade "0.0.2"
There are some commands to be run before actually upgrading the release (moving it to a tmp dir, etc). But I’ve kept it simple for now, more details are available in the exrm docs page on releases.
app.start
taskDoing the above would mean that any task that runs app.start
will error out. Running app.start
would mean that the app is trying to use the same port, which a live release is using. One of those tasks is ecto.migrate
(atleast for now. I’ve read that it’ll change soon with Ecto.Migrator). So migrating the database when a release is running, is going to be nope-nope atleast for now.
Improvise: Let the release start serving the web app automatically. But when mix tasks are run, don’t start the web app.
The phoenix.server
task sets the serve_endpoints: true
. This is an alternative to setting server: true
like we did earlier. This time, we’ll use serve_endpoints
instead. This is independent of app’s name and copyable across apps :)
Add this to the environment config (whichever env is being used):
if System.get_env('SERVER') do
config :phoenix, :serve_endpoints, true
end
Now implode your release and start from scratch. To create a release use SERVER=1 mix release
. Starting the release will serve the web app too.
To run normal mix tasks, run them WITHOUT the SERVER=1
env var. The web app won’t be started :)
mix.exs
frequently is repetitiveImprovise: Use git commit SHAs as versions
Using only a truncated git commit SHA like 3c4dc19
for a version is fine too. But let’s follow semver. Semver allows using custom labels in the version. Having a version like 1.4.1-3c4dc19
is fine by semver. This way I can upgrade actual version numbers only when it rains.
So in our mix.exs
we’ll change this:
def project do
[app: :hello_phoenix,
version: "1.4.1",
elixir: "~> 1.0",
...
and fetch the git commit SHA like this:
def project do
{result, _exit_code} = System.cmd("git", ["rev-parse", "HEAD"])
# We'll truncate the commit SHA to 7 chars. Feel free to change
git_sha = String.slice(result, 0, 7)
[app: :hello_phoenix,
version: "1.4.1-#{git_sha}",
elixir: "~> 1.0",
...
Now to upgrade your release, do:
$ rel/hello_phoenix/bin/hello_phoenix upgrade "1.4.1-3c4dc19"
Feels awkward to type that version manually, but when deploying apps to servers, an automated tool is most likely going to automate this.
If you are looking for a quick & easy way to deploy your Elixir apps to servers, checkout ansible-elixir-stack. It is built on top of Ansible. Tiny details like the ones mentioned here are taken care of for you.