0

I have three apps that I want to run with the rails server at the same time, and I also want the option to kill all the servers from one location.

I don't have much experience with Bash so I'm not sure what command I would use to launch the server for a specific app. Since the script won't be in the app directory plain rails s won't work.

From there, I suppose if I can gather the PIDs of the processes the three servers are running on, I can have the script prompt for user input and whenever something is entered kill the three processes. I'm just unsure of how to get the PIDs.

Additionally, each app has a few environment variables that I wanted to have different values than those assigned in the apps config files. Previously, I was using export var=value before rails s, but I'm not sure how to guarantee each separate process is getting the right variables.

Any help is much appreciated!

5 Answers5

2

The Script

You could try something like the following:

#!/bin/bash

case "$1" in
  start)
    pushd app/directory
    (export FOO=bar; rails s ...; echo $! > pid1)
    (export FOO=bar; rails s ...; echo $! > pid2)
    (export FOO=bar; rails s ...; echo $! > pid3)
    popd
    ;;

  stop)
    kill $(cat pid1)
    kill $(cat pid2)
    kill $(cat pid3)
    rm pid1 pid2 pid3
    ;;

  *)
    echo "Usage: $0 {start|stop}"
    exit 1
    ;;
esac

exit 0

Save this script into a file such as script.sh and chmod +x script.sh. You'd start the servers with a ./script.sh start, and you can kill them all with a ./script.sh stop. You'll need to fill in all the details in the three lines that startup the servers.

Explanation

First is the pushd: this will change the directory to where your apps live. The popd after the three startup lines will return you back to the location where the script lives. The parentheses around the (export blah blah) create a subshell so the environment variables that you set inside the parentheses, via export, shouldn't exist outside of the parentheses. Additionally, if your three apps live in different directories, you could put a cd inside each of the three parantheses to move to the app's directory before the rails s. The lines would then look something like: export FOO=bar; cd app1/directory; rails s ...; echo $! > pid1. Don't forget that semicolon after the cd command! In this case, you can also remove the pushd and popd lines.

In Bash, $! is the process ID of the last command. We echo that and redirect (with >) to a file called pid1 (or pid2 or pid3). Later, when we want to kill the servers, we run kill $(cat pid1). The $(...) runs a command and returns the output inline. Since the pid files only contain the process ID, cat pid1 will just return the process ID number, which is then passed to kill. We also delete the pid files after we've killed the servers.

Disclaimer

This script could use some more work in terms of error checking and configuration, and I haven't tested it, but it should work. At the very least, it should give you a good starting point for writing your own script.

Additional Info

My favorite bash resource is the Advanced Bash-Scripting Guide. Bash is actually a fairly powerful language with some neat features. I definitely recommend learning how bash works!

bmatcuk
  • 453
  • 3
  • 10
  • My apps are in different directories so I would be using cd in the chain of commands. Does this mean I also have to add the corresponding paths in front of pid1, pid2, pid3 when using rm to delete them? –  Oct 03 '13 at 18:06
  • Ah, excellent point! I would recommend keeping all of the pid files in the same location - probably relative to the script itself. So you could do something like: (export FOO=bar; pushd path/to/app1; rails s ...; popd; echo $! > pid1) This will create the pid files relative to the script itself so the stop command will work correctly. – bmatcuk Oct 03 '13 at 20:01
1

Why don't you try capistrano, framework for executing commands in parallel on multiple remote machines, via SSH. Its has lots of recipes to do this.

techvineet
  • 5,041
  • 2
  • 30
  • 28
  • I'm actually curious how to do it in bash, if it's overly complicated I'll of course look elsewhere. –  Oct 03 '13 at 00:13
0

You are probably better off setting up pow.cx, which would run each server as it's needed, rather than having to spin up and shut down servers manually.

Ryenski
  • 9,582
  • 3
  • 43
  • 47
0

You could use Foreman to run, monitor, and manage your processes.

davogones
  • 7,321
  • 31
  • 36
0

I realize I'm late to the party here, but after searching the internet for a good solution to this (and finding this page but few others and none with a full solution) and after trying unsuccessfully to get prax working, I decided to write my own solution to this problem and give it back to the community!

Check out my rdev bash script gist - a bash script you put in your ~/bin directory. This will create a new tab in gnome-terminal for each rails app with the app name and port in the tab's title. It verifies the app launched successfully by checking the port is in use and the process is actually running. It also verifies the rails app shutdown is successful by ensuring the port is no longer in use and the process is no longer running.

Setup is super easy, just change these two config values:

# collection of rails apps you want to start in development (should match directory name of rails project)
# note: the first app in the collection will receive port 3000, the second 3001 and so on
#
  rails_apps=(app1 app2 app3 etc)
#
# The root directory of your rails projects (~/ is assumed, do not include)
#
  projects_root="ruby/projects/root/path"

With this script you can start all your rails apps in one command or stop them all and you can stop, start and restart individual rails apps as well. While the OP requested 3 apps run, this will allow you to run as many as you need with port being assigned in order starting with 3000 for the first app in the list. Each app is started using the proper ruby version thanks to chruby and the .env is sourced on the way up so your app will have everything it needs. Once you are done developing just rdev stop and all your rails apps will be killed and the terminal windows closed.

# Usage Examples:
#
# Show Help
#  ~/> rdev
#    Usage: rdev {start|stop|restart} [app port]
#
# start all rails apps
#  ~/> rdev start
#
# start a single rails app
#  ~/> rdev start app port
#
# stop all rails apps
#  ~/> rdev stop
#
# stop a single rails app
#  ~/> rdev stop app port
#
# restart a single rails app
#  ~/> rdev restart app port

For the record, all testing was done on Ubuntu 18.04. This script requires: bash, chruby, gnome-terminal, lsof and takes advantage of the BASH_POST_RC trick.