Help why is Mix really only a dev tool?

I read that I shouldn’t be using mix to deploy my server in a production like environment and that it is more of a dev tool. I was told that it lazy loads code and that if I use something like releases it won’t. This seems like a very trivial concern because if my app is rather small and all the code is run within the first 30 minutes then after that point all the code has been loaded into memory anyways and this is no longer a problem right?

Are there other benefits or differences between using releases and using mix to deploy a production server? Are there any pitfalls I will run into if I continue to use mix to deploy?

1 Like

At least with distillery you can package some useful scripts into a release. Some are for your application setup, like the scripts that are called at certain stages of your app startup. Some are for starting a remote console to the node.

Are there any pitfalls I will run into if I continue to use mix to deploy?

If you haven’t given a node name to your app node, then you might have difficult time connection to it “remotely”. That’s what I’ve seen people run into the most when using mix to run apps on servers: something goes wrong within the app, and they don’t know how to debug it.

1 Like

Hmmm ok I didn’t know releases allow you to run scripts at different stages, that might be useful at some point but for the time being I don’t really need to do anything like that. As far as remote debugging I usually just kubectl into the cluster and then select a pod and can open a console from there or whatever so that hasn’t been much of a problem. Are there any other main differences?

1 Like

So you run something like iex -S phx.server in a docker container? You should be careful then to not close / stop / crash the iex process while using it since it would also stop the app.

1 Like

mix phx.server

Then how do you connect to the app?

if I need an iex console I can just take one pod down since we have several running and run an iex if I need that for some case. Usually I just kubectl to the pod and look at more environemntal stuff than anything which doens’t require me to connect to the app exactly.

1 Like

I’m not sure I’d be able to debug apps just by looking at env :slight_smile: Sometimes something weird starts going on in some process, so I use rexbug (elixir wrapper for redbug) to trace function invocations / messages received / etc. to find out what’s wrong.

So I guess you’d run into the same issues as the people I mentioned above. Once something within the app breaks and you can’t see any help in the logs, you’ll need to take the app down, add a node name, then take it back up, wait for the problem to reappear, and only then begin debugging.

1 Like

It’s not like you cannot use Mix in production, but releases are the more appropriate way to do so as their sole purpose is to be what you ship to production. I can only support @idi527 that the remote_console you get with distillery might prove itself to be invaluable. It’s never been so easy to debug in production in my experience (like the actual live running code/state not some substitute). Code loading has also been mentioned. Mix also includes a lot of dev related code, which you might not need in production. With elixir comes also exunit, which is usually not something needed in prod.

It’s up to your own if those differences matter enough to not use mix, but there are valid reasons, why people tend to discourage Mix in favor of proper release for production.

Edit:
One difference is also that you don’t need erlang/elixir installed in production if you can match the system on e.g. CI where you compile to the release. So it makes the ops part also simpler on the deployment part (and not only in debugging).

3 Likes

Playing devil’s advocate here, it’s possible to start named node using mix, something like MIX_ENV=prod elixir --name myapp@127.0.0.1 --cookie secret -S mix phx.server or similar. There is also wobserver https://github.com/shinyscorpion/wobserver which might work with any setup and one can use systemd to supervise the mix process (Elixir apps as systemd services - info & wiki). Not trying to say that it’s the way to go, but it’s not that bad (we tried both ways and exrm back then).

One problem with lazy loading that wasn’t mentioned though: Erlang VM has atoms which should not be generated dynamically, people tend to learn it sooner rather then later and use String.to_existing_atom to create atoms safely. Now with lazy loading it’s possible to have atoms in code that wan’t loaded yet which would break the perfectly fine call to the above function, using releases would make sure it never happens.

2 Likes

Exactly. In the Adopting Elixir book we show how to get remote_console, attach/detach and heart working with Mix. However, there are other benefits that you cannot easily achieve without having an explicit release step. To quote the book:

  • Code preloading: The VM has two mechanisms for loading code: interactive and embedded. By default, it runs in the interactive mode which dynamically loads modules when they are used for the first time. The first time your application calls List.first/1, the VM will find the List module and load it. There’s a downside. When you start a new server in production, it may need to load many other modules, causing the first requests to have an unusual spike in response time. Releases run in embedded mode, which loads all available modules upfront, guaranteeing your system is ready to handle requests after booting.

  • Application configuration: When talking about Mix deployment, we discussed the :start_permanent flag and how it sets all applications to :permanent mode, but sometimes you may not want that setting. Maybe you don’t want to restart a given com- ponent should it fail. Mix does not provide fine-grained control over your dependencies but releases do. You can control how to start each application or even set up distributed ones.

  • Multiple releases: Sometimes you must configure the same source code to run in production with different settings than you would use in development. For example, imagine you have both small and large server instances and you’ve measured optimal configurations for both. You can easily build different releases from the same source code, using different configuration and targeting different capabilities.

  • Self-contained: A release does not require the source code to be included in your production artifacts. In fact, it does not even require Erlang or Elixir in your servers, as it is capable of including the whole Erlang runtime itself.

  • Management scripts: Most release tools include a series of scripts that make it straightforward to manage your releases. Those scripts take care of setting up the proper run_erl and heart programs, just as we discussed in the previous section

13 Likes

It’s not something that people do from the start. They start with mix phx.server, then the bugs appear, they take the app down, then they google around, find out about node names and cookies, start the app with a node name, then they wait for the bugs to reappear, and only then they begin to debug with a remote console … With distillery, without any thinking about this up front on the user’s part, everything that’s needed for starting a remote console is already packaged in the release.

As for wobserver, does it allow tracing or remote code execution? If not, then it’s hardly a substitute for a remote console.

1 Like

All true, but there is another side - the deployment with a build step needs extra effort, somewhat more ops, one has to think about including or not including the runtime, building on the right architecture and learning distillery. For a company adopting Elixir this might look like a “not that good part” and we hear it pretty often. The point of mix being not that “uncool” option helps in this regard.

Basically it’s a web version of observer, they came up with a really smart name :smiley:

2 Likes

I have to agree with you Yurko, to me, the deployment of elixir/phoenix apps is whats always been problematic for me and when comparing it to the way other frameworks are deployed releases just have a steeper learning curve. I understand the argument is made that if you’re going to learn how to write elixir apps you should learn how to deploy properly from the start but at the same time when deploying to Heroku you have limitations there as well; so why is deploying via mix much different for someone just getting started?

I know I’m probably in the minority here by saying this but my background is in graphic design and not a programmer first mindset so imho, having options that are easier to get started just makes sense. I may not be a coding ninja like you all, so give me a :hocho: to slice my way to deployment glory :smiley:.

3 Likes

I can relate to your feeling. I felt the same when coming to elixir from php just uploading source files directly. But I think most of it is due to a difference in approach.

Most deployment stories expect you to at least have some kind of runtime of the language available on the server. So a bunch of complexity lies in setting up servers correctly. The same can be done in elixir with mix or releases, which do not bundle erts.

The biggest hurdles in creating releases is imho including erts, as you need to compile on a system with the same architecture (os, …) than your production system. If you do that you don’t need any runtime on the server anymore. You can just upload the release to any matching server and start it. So the complexity is moved from setting up a server to the place where the release is compiled. For example you can just run apps using different versions of erlang/elixir side by side without any problems, which for other languages can be quite the hassle.

This difference is usually not a problem for people managing their own servers, people already using CI/CD, … For those I feel proper releases are quite a win.
Though it certainly can be a problem for people who don’t do that on their own. There I feel mix is the easy way out, as it’s basically the same to other deployments: upload source files and run them.

2 Likes