How To Run Simultaneous Rails Apps With Ease During Development

04 December 2016 on . 4 minutes to read

An artsy quark. Smaller pieces combining to make the whole greater than the sum of the parts, just like proper microservices.

Sometimes while you’re developing Rails apps, especially microservice architectures, you need to be able to run multiple apps on your development machine. Read on to see how I quickly and easily solved that problem using Foreman (Update 12-12-09: Use Heroku Local instead) and a few configuration changes.

Extraction

This exercise is simply a very exact refactor. Instead of having a bunch of port: xxxx configs or Foreman commands across our app, we want to make sure we can easily configure all those ports simultaneously, and in such a manner that we can run apps side by side without having problems like Sidekiq, message queues, redis or any other services between different apps interfering. As an example, if I have multiple apps’ Sidekiqs listening to the same redis instance, something like the following will yield issues:

app1: TestJob.perform_later

app2: NameError: uninitialized constant TestJob

Sidekiq’s NameError: uninitialized constant is because app 2 has picked up app 1’s job. Not what we want to happen.

The simple 3 step refactor for this is as follows:

  • Identify the default port for each service
  • Create a global increment counter
  • Apply this increment counter to each service’s port

Default ports

Across my app, the following are the port defaults:

  • Rails:3000
  • Mailcatcher HTTP:1080
  • Mailcatcher SMTP:1025
  • Redis:6379
  • Sidekiq:6379 (must match Redis)

Increment Counter

Dotenv steps up to the plate:

#.env
PORT_INCREMENT="0" 

For the above, PORT_INCREMENT can be any value, but start with zero.

Mix PORT_INCREMENT In

There are two cases, we either make changes to how services boot (in our Procfile), or within our Ruby on Rails application.

Bash

For this, we’ll use an easy bash trick to perform math. $[x+y], where x and y are integers will take care of it.

#Old Procfile
web: RAILS_ENV='development' bundle exec rails server thin -p $PORT
mailcatcher: RAILS_ENV='development' mailcatcher --foreground
worker: RAILS_ENV='development' bundle exec sidekiq -C ./config/sidekiq.yml
redis: redis-server

This changes to:

#New Procfile
web: RAILS_ENV='development' bundle exec rails server thin -p $[PORT+PORT_INCREMENT]
mailcatcher: RAILS_ENV='development' mailcatcher --foreground --smtp-port $[1025+PORT_INCREMENT] --http-port $[1080+PORT_INCREMENT]
worker: RAILS_ENV='development' bundle exec sidekiq -C ./config/sidekiq.yml
redis: redis-server --port $[6379 + PORT_INCREMENT]

Ruby

#Original config/initializers/sidekiq.rb 
Sidekiq.configure_client do |config|
  config.redis = { size: 3 }
end

Sidekiq.configure_server do |config|
  config.redis = { size: 12 }
end

~~~ruby
#Updated config/initializers/sidekiq.rb 
#CLIENT
Sidekiq.configure_client do |config|
  if Rails.env.development?
    config.redis = {
      size: 3,
      port: (6379 + ENV["PORT_INCREMENT"].to_i)
    }
  else
    config.redis = { size: 3 }
  end
end

#SERVER
Sidekiq.configure_server do |config|
  if Rails.env.development?
    config.redis = { size: 12, port: (6379 + ENV["PORT_INCREMENT"].to_i) }
  else
    config.redis = { size: 12 }
  end
end

Note: You only want this to be configured for your dev environment. Best to leave the other environments as close to the default as possible.

The Result

Before:

Before, or PORT_INCREMENT=0

After:

After, or PORT_INCREMENT=1

Wrap Up

This is step one in developing your applications so that you and your team can easily configure and run multiple apps at the same time. Development should focus on dev work, not banging around keeping your applications separate. I’d love any comments on this PR for improvements, or other spots that similar functionality would be welcome, as I’m always looking to up my game and make everyone’s lives easier, faster, and more efficient.

For the full implementation details, check out this pull request: https://github.com/nrowegt/rails-5-base-app/pull/7/files


If you enjoy having free time and the peace of mind that a professional is on your side, then you’d love to have me work on your project.

Contact or view a list of available services to see how I’ll make your life better, easier and bring satisfaction back into you running your business.