Run separate Process from Mix

I’d appreciate some advice running a separate process from Mix.

I have a timer service, that keeps track of and queues jobs and tasks.
And in order to get that to work, it needs to be a singleton.

Due to some (soon to be removed) environment issues I have 2 dynos on Heroku,
both running my application & Phoenix. Websockets uses Redis since PG2 won’t work
on Heroku.

Heroku’s advice for these situation is to use a ‘clock’ service, ensuring only one instance.
And since the web dynos both call: mix phoenix.server I can’t have both of those instances
adding the time server to my supervision tree.

I’d like to be able to scale my web service independently of my time server (or any other service),
but be able to use my main application’s code. I’m aiming to move towards an umbrella app,
is there an interim step I can take without prying everything apart?
What approaches and/or examples would be suggested for dealing with this?

Are they connected via an Erlang mesh? If so then set it up as a leader (there are a few GenLeader implementations around) or if you expect both to always be up then just take, say, whichever has the lowest PID and let it handle it. Or if not connected then use whichever has the lowest IP or something. Or set it in your config file on whether to enable or not? Lots of options. :slight_smile:

1 Like

Unfortunately thats a the core of the issue, Heroku’s networking model effectively doesn’t allow Erlang nodes to communicate. You get given one port number, and thats it.
So I’m stuck with isolated VMs, and all I have is a startup command.

Your proposed approach is pretty neat, I’ll be poking around GenLeader once I get off Heroku.

Can you set different environment variables per dyno? If so, you can use an environment variable to configure which dyno should have the service running.

2 Likes

Good call! I don’t think you can declare ENV variables per dyno,
however I just checked and Heroku does appear to pass the dyno’s name in.

So I just tried this:

config :my_app, MyApp.SingletonService,
  enabled: System.get_env("DYNO") == "web.1"
env $(cat .env | xargs) DYNO=web.1 iex -S mix
...
iex(1)> Application.get_env(:my_app, MyApp.SingletonService)
[enabled: true]

All HTTP routed processes have to be prepended with web. and are incremented in order.
So I think this is good enough for now, until I can start leveraging multiple nodes properly.
Many thanks everyone!

1 Like