Ecto Repo Umbrella usage

Hi,

I am using Ecto in an umbrella app. Under each app, that uses the database, I have it start the Repo. Something liek this:

def start(_type, _args) do
  import Supervisor.Spec, warn: false

  # Define workers and child supervisors to be supervised
  children = [
    worker(PCommon.Repo, []),
  ]

  opts = [strategy: :one_for_one, name: PCGravity.Supervisor, max_restarts: 1]
  Supervisor.start_link(children, opts)
end

Now, if I start iex, I get the error that it already started. Where would I put this code so that it only starts once? What is the best practice for this?

Well, I don’t know if you really need different pools to the Repo started in each app of your umbrella project. But my first guess to solve this would be:

  • Extract your PCommon.Repo to its own application under your umbrella;
  • Create a supervisor inside this extracted application, start the Repo inside it and export it on its application mix.exs;
  • Every other application that needs this repo, should use this extracted application (don’t forget to add it to the application list in your mix.exs, this grants the application will be started).

I really don’t know if it would work just as I mentioned, but that is what I would try, since it makes sense, architecturally. If you need a more detailed response, just let me know and I’ll be glad to explain as a tutorial.

1 Like

You are 100 percent right. I did that and it worked. In the umbrella app, I just made a common app, then included that app in my other apps in the mix file. I believe that is the best way to make sure ecto is shared amongst all the apps that need it.

1 Like

Nice to hear that! :slight_smile:

Can you mark my comment as the solution so? My OCD is just killing me. :neutral_face: lol

Sure. Basically what I did was create a project called PGCommon. In there I had:

def start(_type, _args) do
    import Supervisor.Spec, warn: false

    # Define workers and child supervisors to be supervised
    children = [
      worker(PGCommon.Repo, [])
    ]

    # See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_one, name: PlacecotCommon.Supervisor]
    Supervisor.start_link(children, opts)

That was in the apps/PGCommon folder’s mix.exs file.

Then each other app, basically included this app in it’s mix.exs file like so:

  defp deps do
     [{:pg_comon, in_umbrella: true}]
  end

So when you do mix.run it goes through all the apps and starts everything up. In this case, the ecto repo will only be started once. I have no idea if this is the right way to do it. One question I still have is how do you make sure the ecto repo will be started first before the other apps. That part I am not sure on yet. If anyone knows, let me know.

1 Like

Well, here it comes:

One thing you probably should be very aware is the application/0 function inside your project config. It is not really necessary to have it, but if you don’t have it, you are basically saying: my application has no other dependency at runtime (yes, the deps method is just for compile time dependencies), and nothing special happens on it.

Now a little more details of what I would put on this method. First, for the PGCommon project, the method would be a little bit like:

  def application do
    [applications: [:logger, :ecto],
     mod: {PGCommon, []}]
  end

Basically this tells Elixir this application depends from logger and ecto applications at runtime, and that the module you should invoke to start the application is the PGCommon module (note: this module must implement the callbacks for the Application module, and this is where you should put the supervisor startup).

Then, in the applications that depend on PGCommon, this is the function I would put:

  def application do
    [applications: [:logger, :pg_common]]
  end

As you probably noticed, the pg_common is a runtime dependency now. This will grant the logger and pg_common applications will be started before the application itself starts. And, as you put the supervisor that starts your Repo on the startup of the pg_common application in the mod key above, you can be sure it will be started even before your application start.

So, this basically respond your question. If you have any other doubt about the application/0 method from the project config, you can run mix help compile.app, it have some other configurations for your application that can be pretty useful.

1 Like