Running different instances of one application on multiple ports using libcluster

I want to run different instances of the same app (not copies of the same app) on the same server (clustering) using different ports, so I used libcluster library and did the following (in application.ex):

def start(_type, _args) do
    import Supervisor.Spec
    # Define Topologies for clustering
    topologies = [
      example: [
        strategy: Cluster.Strategy.Gossip
      ]
    ]
    # List all child processes to be supervised
    children = [
      # For Clustering
      {Cluster.Supervisor, [topologies, [name: MyApp.ClusterSupervisor]]},
      # Start the endpoint when the application starts
      supervisor(MyAppWeb.Endpoint, []),
      {ConCache, [name: :my_cache, ttl_check_interval: false]}
    ]

    # See https://hexdocs.pm/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_one, name: MyApp.Supervisor]
    result = Supervisor.start_link(children, opts)
end

I even tried this:

topologies = [
      example: [
        strategy: Cluster.Strategy.Gossip,
        config: [hosts: [:"a@127.0.0.1", :"b@127.0.0.1",:"b@127.0.0.1",:"d@127.0.0.1"]],
      ]
    ]

but when I tried the following on the server (Ubuntu 18):

 PORT=3000 elixir --sname a -S mix phx.server

then

 PORT=3001 elixir --sname b -S mix phx.server

I get the following error

** (Mix) Could not start application my_app: MyApp.Application.start(:normal, []) returned an error: shutdown: failed to start child: MyAppWeb.Endpoint
    ** (EXIT) shutdown: failed to start child: {:ranch_listener_sup, MyAppWeb.Endpoint.HTTP}
        ** (EXIT) shutdown: failed to start child: :ranch_acceptors_sup
            ** (EXIT) {:listen_error, MyAppWeb.Endpoint.HTTP, :eaddrinuse}


what should I do to make it work.

You should check after starting first server if port 3000 is answering, if not, check port 4000.

I usually have to update my dev config file to do this…

http: [port: 4000],

# Replace by this, which is not the default

http: [
  port: System.get_env("PORT") || 4000
]

… and then I can pass PORT on startup.

After starting the first server, the application is answering correctly on the port,
because my config is like this

http: [
  port: System.get_env("PORT") || 3000
]

the problem is in running the app on other ports on the same time

I have tested this on a Phoenix without libcluster and it works for me.

I also have a libcluster, swarm project, but it uses Cowboy instead of Phoenix.

This might not help You, but I use Epmd strategy, and my config is standard to libcluster doc.

config :libcluster, topologies: [
  example_1: [
    strategy: Cluster.Strategy.Epmd,
    config: [hosts: [
      :node1@localhost,
      :node2@localhost,
      :node3@localhost,
    ]],
  ],

  example_2: [
    strategy: Cluster.Strategy.Gossip,
  ]
]

and I start nodes like this

$ iex --sname node1@localhost -S mix
$ PORT=4001 iex --sname node2@localhost -S mix
$ PORT=4002 iex --sname node3@localhost -S mix

It works, but this is not using Phoenix, but Cowboy.

2 Likes

Just a question, why it worked with the previous command and not this command

$ PORT=4002 iex --sname node3@localhost -S mix phx.server

and would the apps work without determining phx.server or not ?

and when I tried this command
netstat -nlp | grep beam
I got the following output (without 3001 or 3002)

tcp        0      0 0.0.0.0:43145           0.0.0.0:*               LISTEN      p1/beam.smp
tcp        0      0 0.0.0.0:3000            0.0.0.0:*               LISTEN      p2/beam.smp
tcp        0      0 0.0.0.0:40667           0.0.0.0:*               LISTEN      p3/beam.smp
tcp        0      0 0.0.0.0:36507           0.0.0.0:*               LISTEN      p4/beam.smp
udp        0      0 0.0.0.0:45892           0.0.0.0:*                           p5/beam.smp
udp        0      0 0.0.0.0:45892           0.0.0.0:*                           p6/beam.smp
udp        0      0 0.0.0.0:45892           0.0.0.0:*                           p7/beam.smp

ofcourse sudo netstat -nlp | grep 3001 and sudo netstat -nlp | grep 3002 give me nothing

I tried the other approach and it worked correctly, thanks a lot :slight_smile:

but it really bothers me that it didn’t work with libcluster and without knowing why

Hi Din_s,
I see a replication, maybe irrelevant to what you are looking for, but this should not be there, shouldn’t that not be a ‘c’ ?