How to silently start Sinatra + Thin? - ruby

I have a Sinatra::Base webservice which I want to start from a command line Ruby program, so I have this:
# command line program file
require 'mymodule/server'
puts "Running on 0.0.0.0:4567, debugging to STDOUT..."
MyModule::Server.run! bind: '0.0.0.0', port: 4567, environment: :production
This works as expected but it throws out:
$ myscript
Running on 0.0.0.0:4567, debugging to STDOUT...
== Sinatra/1.3.1 has taken the stage on 4567 for production with backup from Thin
>> Thin web server (v1.3.1 codename Triple Espresso)
>> Maximum connections set to 1024
>> Listening on 0.0.0.0:4567, CTRL+C to stop
127.0.0.1 - - [23/Dec/2011 18:44:55] "POST /images HTTP/1.1" 200 360 0.0133
...
And I want it to be silent, and let me output what I want. For example, if I start it not daemonized I want to just see some message from the command line program and the log output, something like:
$ myscript
Running on 0.0.0.0:4567, debugging to STDOUT...
127.0.0.1 - - [23/Dec/2011 18:44:55] "POST /images HTTP/1.1" 200 360 0.0133
...
Also would like to silently shutdown it, hiding:
== Sinatra has ended his set (crowd applauds)
One last question, is this the best option to start a sinatra app with thin from inside an application code(ruby script in this case)?

You can turn off Sinatra logging with
set :logging, false
http://www.sinatrarb.com/configuration.html
As far as whether or not this is the best way to start a sinatra app... You might want to look at the "foreman" gem, and the "Procfile" (which Heroku.com uses) as an example:
http://ddollar.github.com/foreman/

Related

Writing to a file in production with sinatra

I cannot write to a file for the life of me using Sinatra in production.
In my development environment, I can use Logger without a problem and log STDOUT to a file.
It seems like in production, the Logger class is overwritten by the RACK middleware's Logger and it makes things more complicated.
I simply want to write to a file like this:
post '/' do
begin
$log_file = File.open("/home/ec2-user/www/logs/app.log", "w")
...do..stuff...
$log_file.write "INFO -- #{Time.now} --\n #{notification['Message']}"
...do..stuff...
rescue
$log_file.write "ERROR -- #{Time.now} --" + "\njob failed"
ensure
$log_file.close
end
end
The file doesn't get created when I receive a POST request to '/'.
However the file DOES get created when I load the app running pry:
pry -r ./app.rb
I am certain the code inside the POST block is effectively running because new jobs are getting added to the database upon receiving requests..
Any help would be greatly appreciated.
I was finally able to get to the bottom of this.
I changed the nginx user in /etc/nginx/nginx.conf from nginx to ec2-user. (Ideally I would just fix the write permissions for the nginx user but this solution suits me for now.)
Then I ps aux | grep unicorn and saw the timestamp next to the process name: unicorn master -c unicorn.rb -D was 3 days old!!
All this time I was pushing my code the the production server, restarting nginx and never killed and restart the unicorn process.
I removed all the code in my POST block and left only the file creation part
post '/' do
$log_file = File.open("/home/ec2-user/www/logs/app.log", "a")
$log_file.write("test log string")
$log_file.close
end
And the the file was successfully written to upon receiving a POST request.

wrk is displaying odd results on Rack vs Sinatra benchmark

I'm benchmarking a "hello world" equivalent using sinatra and rack.
Command in question wrk -t12 -c400 -d30s: 12 threads, 400 open HTTP connections, 30 seconds.
Rack:
require 'rack'
app = Proc.new do |env|
['200', {'Content-Type' => 'text/html'}, ['A barebones rack app.']]
end
Rack::Handler::Thin.run app
# wrk $ wrk -t12 -c400 -d30s http://localhost:8080
# Running 30s test # http://localhost:8080
# 12 threads and 400 connections
# Thread Stats Avg Stdev Max +/- Stdev
# Latency 11.82ms 38.97ms 488.51ms 99.32%
# Req/Sec 705.04 568.62 2.20k 61.82%
# 16576 requests in 30.08s, 1.55MB read
# Socket errors: connect 157, read 274, write 0, timeout 0
# Requests/sec: 551.05
# Transfer/sec: 52.74KB
Sinatra:
require 'sinatra'
get '/' do
status 200
headers \
'Content-Type' => 'text/html'
'A barebones rack app.'
end
# wrk $ wrk -t12 -c400 -d30s http://localhost:4567
# Running 30s test # http://localhost:4567
# 12 threads and 400 connections
# Thread Stats Avg Stdev Max +/- Stdev
# Latency 40.12ms 90.46ms 1.39s 98.67%
# Req/Sec 265.47 147.50 1.17k 73.15%
# 90322 requests in 30.08s, 18.78MB read
# Socket errors: connect 157, read 333, write 0, timeout 0
# Requests/sec: 3002.52
# Transfer/sec: 639.21KB
Specs:
If both Rack and Sinatra run Thin, how come Sinatra manages 3002.52~ req/s while pure Rack manages only 551.05 req/s? What am I missing?
I didn't install wrk, I wasn't in the mood for an install, but I ran both your examples using time:
# run.sh
for i in {1..1000}
do
curl localhost:8080/ > /dev/null 2>&1
done
# sinatra, run via `bundle exec ruby sinatra.rb -p 8080`
$ time sh run.sh
sh run.sh 3.67s user 2.79s system 66% cpu 9.768 total
# rack, run via `bin/rackup config.ru`
$ time sh run.sh
sh run.sh 3.65s user 2.87s system 74% cpu 8.799 total
# sinatra with the puma server, by adding the line `set :server, "puma"`
$ time sh run.sh
sh run.sh 3.67s user 2.71s system 92% cpu 6.924 total
I got very similar results, so perhaps it's something to do with wrk or your system. I'm running OSX Mavericks, but I found this answer that says to benchmark with time you should really use chrt to avoid contention with other processes. I'm not sure what the OSX equivalent of chrt is though. Perhaps that's what is happening on your system, or perhaps the ports are running at different speeds, for whatever reason.
I also sandboxed my gems using bundle install --binstubs --path vendor.noindex, perhaps that would have an effect on your system too.
Otherwise, I can't see any reason for such disparity. I a little surprised by the results I got as I'd expect Sinatra to be quite a bit heavier than Rack, but perhaps things seem different with more complex or larger apps. Or perhaps not, Sinatra is such a neat little library.

Thor Start Jekyll then Open Page in Browser

Hi I want Thor to start a server - Jekyll / Python / PHP etc then open the browser
However the starting is a blocking task.
Is there a way to create a child process in Thor; or spawn a new terminal window - couldnt see and google gave me no reasonable answers.
My Code
##
# Project Thor File
#
# #use thor list
##
class IanWarner < Thor
##
# Open Jekyll Server
#
# #use thor ian_warner:openServer
##
desc "openServer", "Start the Jekyll Server"
def openServer
system("clear")
say("\n\t")
say("Start Server\n\t")
system("jekyll --server 4000 --auto")
say("Open Site\n\t")
system("open http://localhost:4000")
say("\n")
end
end
It looks like you are messing things up. Thor is in general a powerful CLI wrapper. CLI itself is in general singlethreaded.
You have two options: either to create different Thor descendents and run them as different threads/processes, forcing open thread/process to wait until jekyll start is running (preferred,) or to hack with system("jekyll --server 4000 --auto &") (note an ampersand at the end.)
The latter will work, but you still are to control the server is started (it may take a significant amount of time.) The second ugly hack to achieve this is to rely on sleep:
say("Start Server\n\t")
system("jekyll --server 4000 --auto &")
say("Wait for Server\n\t")
system("sleep 3")
say("Open Site\n\t")
system("open http://localhost:4000")
Upd: it’s hard to imagine what do you want to yield. If you want to leave your jekyll server running after your script is finished:
desc "openServer", "Start the Jekyll Server"
def openServer
system "clear"
say "\n\t"
say "Starting Server…\n\t"
r, w = IO.pipe
# Jekyll will print it’s running status to STDERR
pid = Process.spawn("jekyll --server 4000 --auto", :err=>w)
w.close
say "Spawned with pid=#{pid}"
rr = ''
while (rr += r.sysread(1024)) do
break if rr.include?('WEBrick::HTTPServer#start')
end
Process.detach(pid) # !!! Leave the jekyll running
say "Open Site\n\t"
system "open http://localhost:4000"
end
If you want to shutdown the jekyll after the page is opened, you are to spawn the call to open as well and Process.waitpid for it.

How to shutdown Ruby XMLRPC server?

I'm testing Ruby XMLRPC support right now. It all works fine, except XMLRPC::Server#shutdown.
If I run the following Ruby 1.9.3 test code, it fails to shut down the server on both Windows 7 and OSX 10.7:
# server.rb
require "xmlrpc/server"
require 'thread'
Thread.new { sleep 10; $server.shutdown() }
$server = XMLRPC::Server.new( 1234 )
$server.add_handler( "test" ) { true }
$server.serve()
# client.rb
require "xmlrpc/client"
server = XMLRPC::Client.new( "localhost", "/", 1234 )
loop { server.call( "test" ); sleep 0.1 }
After ten seconds, the server writes "INFO going to shutdown ..." to stdout, but won't actually shut down and continues to handle incoming requests. What am I doing wrong?
Have you noticed that without incoming requests it shutdowns properly? Also, after you end the client, it will shut down as it should, returning :Stop symbol. It waits for the client to stop pumping data before shutting down.
I have examined XMLRPC::Server source code. It seems a bug/feature that prevents shutdown if client uses connection with keep-alive HTTP flag.
The workaround is to use call_async instead of call.

Writing a simple webserver in Ruby

I want to create an extremely simple web server for development purposes in Ruby (no, don’t want to use ready solutions).
Here is the code:
#!/usr/bin/ruby
require 'socket'
server = TCPServer.new('127.0.0.1', 8080)
while connection = server.accept
headers = []
length = 0
while line = connection.gets
headers << line
if line =~ /^Content-Length:\s+(\d+)/i
length = $1.to_i
end
break if line == "\r\n"
end
body = connection.readpartial(length)
IO.popen(ARGV[0], 'r+') do |script|
script.print(headers.join + body)
script.close_write
connection.print script.read
end
connection.close
end
The idea is to run this script from the command line, providing another script, which will get the request on its standard input, and gives back the complete response on its standard output.
So far so good, but this turns out to be really fragile, as it breaks on the second request with the error:
/usr/bin/serve:24:in `write': Broken pipe (Errno::EPIPE)
from /usr/bin/serve:24:in `print'
from /usr/bin/serve:24
from /usr/bin/serve:23:in `popen'
from /usr/bin/serve:23
Any idea how to improve the above code to be sufficient for easy use?
Versions: Ubuntu 9.10 (2.6.31-20-generic), Ruby 1.8.7 (2009-06-12 patchlevel 174) [i486-linux]
The problem appears to be in the child script, since the parent script in your question runs on my box (Debian Squeeze, Ruby 1.8.7 patchlevel 249):
I created the dummy child script bar.rb:
#!/usr/bin/ruby1.8
s = $stdin.read
$stderr.puts s
print s
I then ran your script, passing it the path to the dummy script:
$ /tmp/foo.rb /tmp/bar.rb
The I hit it with wget:
$ wget localhost:8080/index
And saw the dummy script's output:
GET /index HTTP/1.0^M
User-Agent: Wget/1.12 (linux-gnu)^M
Accept: */*^M
Host: localhost:8080^M
Connection: Keep-Alive^M
^M
I also saw that wget received what it sent:
$ cat index
GET /index HTTP/1.0
User-Agent: Wget/1.12 (linux-gnu)
Accept: */*
Host: localhost:8080
Connection: Keep-Alive
It worked the same no matter how many times I hit it with wget.
The Ruby Web Servers Booklet describes most of web server implementation strategies.
With the Ruby Webrick Lib you have an easy Library to build a webserver.
http://www.ruby-doc.org/stdlib/libdoc/webrick/rdoc/

Resources