2
\$\begingroup\$

I wanted to write a script, which starts a rails app, and opens it in the browser.
I'm trying to implement this in a peculiar way though - I expect two things:

  1. the script must wait until the server is started, then open the browser within a short time
  2. when I stop the script (Ctrl+C), the server process must stop.

The script I've written actually works, but I was wondering if there is a simplerr/more standard/more correct way of writing it.

The script is written for linux, but it's not meant to be platform specific - or more precisely, anything except Windows.

PROJECT_DIR = '/path/to/app'
POLLING_TIME = 0.1
SERVER_STARTED_REGEX = /WEBrick::HTTPServer#start/
BROWSER_COMMAND = 'browser http://localhost:3000 &'
Dir.chdir( PROJECT_DIR )
thread = Thread.new do
 IO.popen( 'script/rails server 2>&1' ) do | io |
 Thread.current[ :last_server_line ] = io.gets while true
 end
end
sleep POLLING_TIME while thread[ :last_server_line ] !~ SERVER_STARTED_REGEX
`#{ BROWSER_COMMAND }`
thread.join
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Oct 28, 2013 at 22:42
\$\endgroup\$
2
  • \$\begingroup\$ Do you mean what anybody will edit you post, with better script, or make an answer below? \$\endgroup\$ Commented Nov 5, 2013 at 15:03
  • \$\begingroup\$ @majioa It's best to use the answer feature, so that others have the chance to see the original question and provide answers of their own. \$\endgroup\$ Commented Nov 5, 2013 at 20:13

1 Answer 1

1
\$\begingroup\$

This was an interesting one. Thank you :)

I dug around in the rails code and poked at webrick and rack for a while and this is what I came up with:

PROJECT_DIR = ENV['PROJECT_DIR'] || '/path/to/app'
BROWSER_COMMAND = ENV['BROWSER_COMMAND'] || 'browser http://localhost:3000 &'
PORT = ENV['PORT'].to_i || 3000
require "#{PROJECT_DIR}/config/environment.rb"
thread = Thread.new do
 Rack::Handler::WEBrick.run Rails.application, Port: PORT
end
`#{ BROWSER_COMMAND }`
Rack::Handler::WEBrick.shutdown
thread.join

This approach is actually borrowed from rack's webrick handler.

I load the environment prior to actually starting the webrick server making any waits unnecessary for me. If that should be necessary for you, I'm sure you could add it.

Then I pretty much stuck to what you did, putting the actual server into a thread. The Handler already provides that neat shutdown method.

Oh, I also took the liberty of adding some ENV variables so you can put this script into a file and run it from where ever you want.

EDIT: In the comments Marcus pointed out, that in order to resolve the timing issue, one can set the closure (block variable) from WEBrick.run {|server|} to a thread-local variable that can be polled afterwards.

There might also be ways to exploit Celluloid for messaging between the different threads.

answered Nov 5, 2013 at 15:02
\$\endgroup\$
3
  • \$\begingroup\$ The logic is appropriate, but there is a bug! The completion of the application start is asynchronous, so that the browser starts before actually something is listening on the port. In addition to that, the webrick shutdown raises an error if the app is not fully started! \$\endgroup\$ Commented Nov 16, 2013 at 15:17
  • \$\begingroup\$ I've actually found a workaround - the WEBrick.run {|server|} variable can be stored in the thread local storage. immediately afterwards, it can be polled at intervals, until it's not nil. at that point, the server is ready. \$\endgroup\$ Commented Nov 16, 2013 at 15:25
  • \$\begingroup\$ Yeah, I mentioned that one in my answer. It was not necessary for me since my browser took a while to start and the server was ready by then. Glad you managed to figure it out. \$\endgroup\$ Commented Nov 16, 2013 at 20:27

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.