Goliath not being asynchronous - ruby

I am running a simple goliath server on my localhost with Ruby 1.9.3, and it's not running http requests asynchronously. Here's the code:
require 'goliath'
require 'em-synchrony'
require 'em-synchrony/em-http'
class Server < Goliath::API
use Goliath::Rack::Validation::RequestMethod, %w(GET PUT POST)
def initialize
super
puts "Started up Bookcover server... Let 'em come!"
end
def response(env)
thumbnail_cover_url, large_book_cover_url = ["http://riffle-bookcovers.s3.amazonaws.com/B00GJYXA5I-thumbnail.jpg", "http://riffle-bookcovers.s3.amazonaws.com/B00GJYXA5I-original.jpg"]
puts "start"
a = EM::HttpRequest.new(thumbnail_cover_url).get
b = EM::HttpRequest.new(large_book_cover_url).get
puts "done"
[200, {}, "Hello World"]
end
end
When I run ab -n 100 http://127.0.0.1:9000/ I can see it waits for each request to be done, which means that the calls are blocking.
However, according to the documentation Goliath uses Em-synchrony to let me write "synchronous-looking" code, which is not the case here.
I would appreciate any hints and comments!

Credits go to igrigorik for the answer. I quote from his answer here:
You also need to specify the concurrency level when you run ab... e.g.
ab -c 10 :)
Also, make sure you run it in production mode (-e prod).

Related

Sinatra app executes during load instead of after run method issued

This is a stripped down example of a real app I am building. When I execute my app, this is the result I get. You'll notice that it says that it is running before it is starting. You'll also notice it never says running after the start is issued.
bundle exec rackup
Using thin;
Sapp::App running.
Starting Sapp::App
== Sinatra (v1.4.7) has taken the stage on 4567 for development with backup from Thin
Thin web server (v1.7.0 codename Dunder Mifflin)
Maximum connections set to 1024
Listening on localhost:4567, CTRL+C to stop
My config.ru is:
# http://www.rubydoc.info/gems/webmachine/Webmachine/Adapters/Rack
$started = false
require 'thin'
require 'sinatra'
set :server, (ENV['RACK_ENV'] == 'production' || ENV['RACK_ENV'] == 'staging' ? 'rack' : 'thin')
puts "Using #{settings.server};"
load 'webmachine/adapters/rack.rb'
load File.join(File.dirname(__FILE__), 'sapp.rb')
$started = true
puts 'Starting Sapp::App'
#Sapp::App.run!
Sinatra::Application.run!
I am setting $started just to try to fix this problem, but it doesn't help. My app is executed before it is set. I could control that but, and this is the rub, it does not execute after the run is issued.
sapp.rb is:
ENV['RACK_ENV'] ||= 'development'
Bundler.setup
$: << File.expand_path('../', __FILE__)
$: << File.expand_path('../lib', __FILE__)
require 'dotenv'
Dotenv.load(
File.expand_path("../.env.#{ENV['RACK_ENV']}", __FILE__),
File.expand_path("../.env", __FILE__))
module Sapp
class App < Sinatra::Application
puts 'Sapp::App has been started.' if $started
puts 'Sapp::App running.'
end
end
In the end, if nothing else, Once it says "Starting Sapp::App", it should also say "Sapp::App has been started." and "Sapp::App running."
For the record, both these options do the same thing:
Sapp::App.run!
Sinatra::Application.run!
Okay, I get it. I put the code in a class, but not it a method. Load or require both run open code like this. I need to wrap it in methods, and execute the methods, to do what I want to do.
Sinatra examples, which I followed, don't make this clear and simply avoid the topic. Many are so simple it doesn't make a difference, and some are just coded within the config.ru. I am coming from Rails and, while I knew this from Rails, it didn't make much of a difference since the vast majority of the code already exists in methods.

Requiring grape hugely slows down Goliath

I've written a 'Hello World' app using Goliath, and I decided to mount Grape on top of it:
#!/usr/bin/env ruby
require 'rubygems'
require 'bundler/setup'
Bundler.setup :default
require 'goliath'
require 'grape' # <-- Comment out this line will hugely increase performance, but why?
class Server < Goliath::API
def response(env)
[200, {}, 'Hello, world!']
end
end
I benchmarked it:
ab -n 1000 -c 100 http://localhost:9000/
It shows that about 250 requests can be handled per second. But when I comment out the line require 'grape', this value suddenly increased to about 700. Can anybody answer why the simple require can bring such a huge difference?
P.S. I use MRI 2.2.2
Are you running Goliath in production mode? You have to set -e prod of it will do code re-loading on each request.

Kill all threads on terminate

I'm trying to create an app in ruby which can be started from command line and it does two things: runs a continous job (loop with sleep which runs some action [remote feed parsing]) with one thread and sinatra in a second thread. My code (simplified) looks like that:
require 'sinatra'
class MyApp < Sinatra::Base
get '/' do
"Hello!"
end
end
threads = []
threads << Thread.new do
loop do
# do something heavy
sleep 10
end
end
threads << Thread.new do
MyApp.run!
end
threads.each { |t| t.join }
The above code actually does it's job very well - the sinatra app is started an available under 4567 port and the do something heavy task is beeing fired each 10 seconds. However, i'm not able to kill that script.
I'm running it with ruby app.rb but killing it with ctrl + c is not working. It kills just the sinatra thread but the second one is still running and, to stop the script, i need to close the terminal window.
I was trying to kill all the threads on SIGNINT but it's also not working as expected
trap "SIGINT" do
puts "Exiting"
threads.each { |t| Thread.kill t }
exit 130
end
Can you help me with this? Thanks in advance.
To trap ctrl-c, change "SIGINT" to "INT".
trap("INT") {
puts "trapping"
threads.each{|t|
puts "killing"
Thread.kill t
}
}
To configure Sinatra to skip catching traps:
class MyApp < Sinatra::Base
configure do
set :traps, false
end
...
Reference: Ruby Signal module
To list the available Ruby signals: Signal.list.keys
Reference: Sinatra Intro
(When I run your code and trap INT, I do get a Sinatra socket warning "Already in use". I presume that's fine for your purposes, or you can solve that by doing a Sinatra graceful shutdown. See Sinatra - terminate server from request)
Late to the party, but Trap has one big disadvantage - it gets overriden by the webserver. For example, Puma sets several traps which basically makes your one never to be called.
The best workaround is to use at_exit which can be defined multiple times and Ruby makes sure all blocks are called. I haven't tested this if it would work for your case tho.

How do you test Postgres's LISTEN / NOTIFY with ActiveRecord?

Assuming I'm using the pg gem and RSpec, what approach should I take to properly test that my LISTEN and NOTIFY statements are working? pg's wait_for_notify blocks, so it seems like I wouldn't be able to "notify, then listen", or "listen, then notify". Am I overlooking something?
For example:
it "notifies" do
conn = ActiveRecord::Base.connection
it_ran = false
conn.execute "LISTEN my_channel"
conn.execute "NOTIFY my_channel, 'hello'"
conn.wait_for_notify(1) do |channel, pid, payload|
it_ran = true
end
expect(it_ran).to eq true
end
Edit:
This works in the controller, and even the rails console, but for some reason it doesn't work in an RSpec test. Strangely, using the pg gem directly does work. Why might ActiveRecord not be working in this scenario?
wait_for_notify() only blocks if it needs to. That is, when there isn't already something in the notification queue.
In your code, there will already be a notification in the queue based on your first NOTIFY, so wait_for_notify() will return immediately and it_ran will be set.
If I rip out the ActiveRecord stuff and just use pg directly, this is exactly what happens.
Turns out the problem was with DatabaseCleaner. With that I tried using other strategies instead of transaction, but nothing worked; it seems like the only way to get LISTEN / NOTIFY working on an ActiveRecord connection is to disable it for that one test.
Here's how I ended up disabling DatabaseCleaner for a specific test. In my support configuration file:
RSpec.configure do |config|
# BEFORE:
# config.before(:each) do
# DatabaseCleaner.strategy = :transaction
# end
# AFTER:
config.before(:each) do |test|
unless test.metadata[:no_database_cleaner]
DatabaseCleaner.strategy = :transaction
end
end
end
In my spec file:
RSpec.describe "Postgres LISTEN / NOTIFY" do
it "notifies", :no_database_cleaner => true do
# [clipped]
end
end
Now anytime I need to test for LISTEN / NOTIFY, I add :no_database_cleaner => true to the it block.

very basic ruby/sinatra/heroku/debugging question: how to see output of puts and p?

I'm trying to build a very simple sinatra app deployed on heroku.
our app is not outputting stuff to a web browser, it's communicating with another computer via an API. so my usual trick of just printing a little extra debugging info to the browser while I'm using the app doesnt work.
the sample code I've seen for related apps show multiple 'puts' or 'p' statement used ot sort of see what's going on...
where does the output go that I can see that output as the program executes, or afterwards.
and in general, if you're flailing around with code hosted at Heroku that's just not doing what you want, what IS the easiest way to at various places in the code output messages like "foo equals 123" so you can see that output to figure out what's happening in the code?
p and puts dont output so the logs I can see when I type "heroku logs" for example...
If you use a cedar stack, try to put a line bellow in config.ru,
$stdout.sync = true
http://devcenter.heroku.com/articles/ruby#logging
Original post was in February 2011, and Cedar stack was introduced in May, so this doesn't seem to be help for original question, but some of you may find this could be help.
http://blog.heroku.com/archives/2011/5/31/celadon_cedar/
According to http://docs.heroku.com/logging you should be able to have puts and p just go to your log if you add the basic logger (which has apparently been added by default to all apps created after February 2nd, 2011).
For non-Heroku basic log-to-file with Sinatra and Logger:
require 'logger'
Dir.mkdir('logs') unless File.exist?('logs')
$log = Logger.new('logs/output.log','weekly')
configure :production do
$log.level = Logger::WARN
end
configure :development do
$log.level = Logger::DEBUG
end
get "/" do
$log.debug "Hello, World!"
end
This will work fine. test_logging.rb
require 'sinatra'
require 'logger'
enable :logging
before do
logger.level = Logger::DEBUG
end
get '/' do
logger.debug "Handling 'hello world' request."
logger.info "Hello world."
return "<h1>Hello World</h1>"
end
See here for tips on how to write to the Logger: http://mikenaberezny.com/2007/02/24/rails-logging-tips/
The example given is:
class HomeController < ActionController::Base
def index
logger.info 'informational message'
end
end
This is the line that works for me:
# On config.ru, before run:
enable :logging, :dump_errors, :raise_errors

Resources