How to split phoenix umbrella app?

I want to split my app into 2 parts:

server 1: Cache // will feed data to server #2
server 2: Webserver // serve static assets and handle API requests(via #2)

I imagine first step would be splitting app into umbrella project? But I don’t quite understand how to then “distribute” this umbrella project to different nodes(servers). Any examples of last part?

1 Like

I’m not 100% on your overall goal, but it sounds like you want to split up the responsibilities of your project into multiple apps. So yes, you would create an umbrella project that would contain multiple apps. Given your description, this is how I would set it up:

  • coolness_umb (project)
    • coolness (app)
    • coolness_cache (app)
    • coolness_web (phoenix app)

The actual “app” logic would go in the coolness app. There are many discussions around about the web server’s distinction from the business logic itself, like here, here, here, and it goes on…(there is even a meta-question here on how important/non-important this is)._ :sweat_smile: I think the structure I’ve given is reasonable for moderate sized projects.

As for the cache, I would point out that for an app just starting it may not even be necessary to implement a cache early on:

Phoenix (without caching) will perform better than Rails (with caching).
We already know this is true on a small app, and we can’t wait to see
how it pans out on a large one. We don’t expect to completely avoid
caching with Phoenix, but it would be nice to avoid having to do it
aggressively and early, as we have had to on our Rails projects to get
reasonable performance and latency. Rails makes it “easy,” but it’s
still time consuming and hard to get right. It also creates friction
that reduces productivity.

I personally implemented a simple cache in ibgib using ets (thus making it local). But I gradually realized that processes on the BEAM can themselves act as an awesome caching mechanism. But I digress… (often).

I recently deployed ibgib to AWS with distillery and docker, and in doing so I only created one release for my entire umbrella application. I ended up with three containers:

  1. Nginx - acts as an https/bare URL redirect only right now.
  2. web - contains my entire umbrella application which includes both the business app (ib_gib) and the web app (web_gib).
  3. postgres - for the data layer.

So I don’t have personal experience with the multiple releases in an umbrella. However, it is mentioned in distillery’s umbrella documentation that you can make multiple release configurations to cherry pick which apps to include in which release. So I believe you will end up in your “release” phase of deployment doing two releases, something like (I’m not 100% on the syntax):

Server 1: mix release --profile=cache:prod
Server 2: mix release --profile=web:prod

EDIT: Per that same distillery documentation page, this will automagically resolve dependencies.

At this point you would have two tars that contain your release and you would deploy each as you would deploy a single release. I personally think Docker is the way to go, with either Kubernetes or Swarm. Also there is Rancher for a higher-level abstraction over the orchestration. Others could speak more to non-Docker approaches. But assuming you would use one of these, (I haven’t personally gotten to clustering yet) a good site I’ve found is on Clustering Elixir nodes on Kubernetes. The “Addendum” section speaks to using a distillery release and vm environment variables for node configuration.