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:
- the script must wait until the server is started, then open the browser within a short time
- 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
-
\$\begingroup\$ Do you mean what anybody will edit you post, with better script, or make an answer below? \$\endgroup\$Малъ Скрылевъ– Малъ Скрылевъ2013年11月05日 15:03:00 +00:00Commented 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\$CMW– CMW2013年11月05日 20:13:01 +00:00Commented Nov 5, 2013 at 20:13
1 Answer 1
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.
-
\$\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\$Marcus– Marcus2013年11月16日 15:17:15 +00:00Commented 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\$Marcus– Marcus2013年11月16日 15:25:36 +00:00Commented 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\$CMW– CMW2013年11月16日 20:27:16 +00:00Commented Nov 16, 2013 at 20:27