habutre

habutre

Application communication best practices

Hi all!

This is my very first question here!

I was playing a bit with Phoenix and Elixir in a solution where I would like to use Phoenix as a client application which will provide solely a web interface for backend services allowing in future using other interfaces such as CLI or integration with other technologies through messaging or http.

Between Phoenix and Backend Elixir communication I would like ideally to take advantage of Erlang/Elixir ecosystem and make that communication through processes and I decide to use Genserver for that.

What I did was define the callback handle_call in the backend service and on client I wrap the Genserver calls in a MyApp.BackedEndApp.Client module which uses purely Genserver.call to invoke the backend functions.

I had received some critics from my team members about that approach. What could be a best practice in that case when I want to keep client and server decoupled in the same time I want to take the ecosystem advantages? I mean without HTTP/Rest or Messaging communication

Marked As Solved

joaothallis

joaothallis

Is there any reason why the web code has to stay in another node (separete machine)?

If the codes can stay on the same machine why not call the function directly? For me this is the best practice and the simplest.

One option to decouple and use the same machine is to use RabbitMQ or something, but for a simple API I understand it as a bad practice.

If you would you like build microservices was some approaches: http://www.ubazu.com/microservice-approaches-in-elixir

It’s worth seeing: http://www.ubazu.com/decouple-your-elixir-application-from-phoenix-and-ecto

Also Liked

al2o3cr

al2o3cr

Have you considered using… nothing? Let’s walk through a typical Phoenix + Ecto application to explain what I mean.

(h/t to @jola, this is a long version of that earlier comment)

There are two big clumps of processes running: database connections and acceptors.

The application’s Repo is a single process, started at boot, and manages a pool of DBConnection processes, keeping track of which connections are checked out and handling failures.

A Phoenix endpoint uses Cowboy (and ultimately Ranch) to start a bunch of “acceptor” processes which (as the name might suggest) accept incoming TCP connections and start a new “handler” process that does the actual work (here’s a diagram and additional discussion).

That process handles running the per-request Phoenix code as well as user-defined plugs and eventually calls the specified function in the controller. When that code calls functions like Ecto.Repo.insert, Ecto checks out a connection - borrowing it from the DBConnection process that holds it when idle - and interacts with the database.

Notably absent here is a process boundary: some of the code that gets executed is defined in modules within the Phoenix “app” (routing, plugs, controllers), and some comes from the Ecto “app” (schemas, changesets) but all of it executes within that single “handler” process created for the specific HTTP request.

This is what the GenServer docs mean by “use processes only to model runtime properties, not code organization”. The runtime property desired here is per-HTTP-request concurrency.

On the other hand, having an EctoApp GenServer that every HTTP request interacts with would result in a bottleneck at that GenServer’s message queue.

So “nothing” at the beginning of this post is a little hyperbolic, but “a function call” is pretty close. The BEAM has a lot of powerful architectural features, but it’s vitally important to understand the philosophy underpinning them to use them correctly. GenServers != microservices

habutre

habutre

You got my point, since I came mostly from Java world where the lately there is a big movement towards microservices and event-driven architectures I tend to use more or less the same approach with Elixir.

Since I didn’t get constructive driven-by-example feedback from my aforementioned colleagues I end up here trying to find out the Elixir-way to write code that is decoupled, distributed and/or isolated among contained services holding mainly business logic.

I really appreciate all points that people brought me here and help me a lot. Thanks @kokolegorille @jola @peerreynders @axelson @al2o3cr and @joaothallis for spend your time to help me on my journey to become a good Elixir Dev.

jola

jola

Based on your description I would recommend against GenServer. The thing is that the way Phoenix works is that it spawns a process for each request that comes in. This allows it to scale nicely over multiple cores. Assuming you start a single process to handle all the work you are effectively turning your app single-threaded. You’d get around that if you create a pool of processes etc, but that’s a lot of effort for what gain?

I would not use GenServer for this. Just create a client module and call those functions. This means your business code runs in every process spawned for requests, the way it is intended, and you still get the separation of concern and decoupling that you’re interested in. I don’t understand why you’d have two apps speaking over “HTTP/Rest” if all you’re concerned with is decoupling.

Where Next?

Popular in Questions Top

Tee
can someone please explain to me how Enum.reduce works with maps
New
chrisalley
ExUnit now has describe blocks which is a welcome addition coming from RSpec. In the docs, it states that nested hierarchies of describe ...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lists...
New
mgjohns61585
Could someone help me? I’m making my first elixir program, number guessing game. I can’t figure out how to convert the user’s guess from ...
New
tduccuong
Hi, is there any work on GUI with Elixir, that is similar to Electron/Javascript? My idea is to bundle Phoenix and BEAM into a single se...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
itssasanka
Hi all, Trying to get some more clarity over utc_datetime and naive_datetime for Ecto: The documentation above suggests that while ...
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
PeterCarter
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => ...
New

Other popular topics Top

marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
New
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => ...
New

We're in Beta

About us Mission Statement