I'm trying to understand how to use various non-blocking IO libraries in Ruby and made a simple app for testing using Sinatra,
# proxy.rb
require 'bundler/setup'
require 'sinatra/base'
require 'sinatra/synchrony'
require 'faraday'
class ProxyApp < Sinatra::Base
register Sinatra::Synchrony
get "/proxy" do
conn = Faraday.new("http://mirror.yandex.ru") do |faraday|
faraday.use Faraday::Adapter::EMSynchrony
end
conn.get "/ubuntu-releases/precise/ubuntu-12.04.1-alternate-i386.iso"
"Hello, world"
end
get "/" do
"Hello, world"
end
end
As far as I understand, downloading a file using non-blocking IO should allow other requests to execute, but it doesn't - if I'm using ab to open /proxy path (I'm using Thin as an app server), request to / takes a very long time. Am I doing something wrong?
Sinatra::Synchrony? Why?
config.ru:
require File.join Dir.pwd, 'proxy.rb'
run Proxy
Gemfile:
source 'https://rubygems.org'
gem 'sinatra'
gem 'thin'
gem 'faraday'
gem 'em-synchrony'
gem 'em-http-request'
gem 'rack-fiber_pool'
proxy.rb:
require 'bundler'
Bundler.require
class Proxy < Sinatra::Base
use Rack::FiberPool
get "/proxy" do
conn = Faraday.new("http://mirror.yandex.ru") do |faraday|
faraday.use Faraday::Adapter::EMSynchrony
end
conn.get "/ubuntu-releases/precise/ubuntu-12.04.1-alternate-i386.iso"
"Hello, world"
end
get "/" do
"Hello, world"
end
end
Start:
thin start -d
wget localhost:3000/proxy
In another terminal:
wget localhost:3000/
The reply is immediate for /, no matter how many requests to /proxy you do in parrallel.
Related
This is my web app:
class Front < Sinatra::Base
configure do
set :server, :puma
end
get '/' do
'Hello, world!'
end
end
I start it like this (don't suggest to use Rack, please):
Front.start!
Here is my configuration object for Puma, which I don't know how to pass to it:
require 'puma/configuration'
Puma::Configuration.new({ log_requests: true, debug: true })
Seriously, how?
Configuration is tightly connected to a way in which you run puma server.
The standard way to run puma - puma CLI command. In order to configure puma config file config/puma.rb or config/puma/<environment>.rb should be provided (see example).
But you asked how to pass Puma::Configuration object to puma. I wonder why you need it but AFAIK you need to run puma server programmatically in your application code with Puma::Launcher(see source code)
conf = Puma::Configuration.new do |user_config|
user_config.threads 1, 10
user_config.app do |env|
[200, {}, ["hello world"]]
end
end
Puma::Launcher.new(conf, events: Puma::Events.stdio).run
user_config.app may be any callable object (compatible with Rack interface) like Sinatra application.
Hope it's helpful.
Do you want to pass exactly an object or just a configuration in general? For the last option it's possible, but Puma will not log anything anyway (I'm not sure, but seems like you worry exactly about logging settings for Puma).
#!/usr/bin/env ruby
# frozen_string_literal: true
require 'bundler/inline'
gemfile(true) do
gem 'sinatra'
gem 'puma'
gem 'openssl'
end
require 'sinatra/base'
class Front < Sinatra::Base
configure do
set :server, :puma
set :server_settings, log_requests: true, debug: true, environment: 'foo'
end
get '/' do
'Hello, world!'
end
end
Front.start!
I'm trying to set up a simple Sinatra app with I18n, following the recommended Sinatra recipe, and using Rack:Locale to determine the language.
My app.rb:
require 'rubygems'
require 'sinatra'
require 'rack/contrib'
require 'i18n'
require 'i18n/backend/fallbacks'
require 'tilt/haml'
use Rack::Locale
configure do
I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)
I18n.load_path = Dir[File.join(settings.root, 'locales', '*.yml')]
I18n.backend.load_translations
end
helpers do
def t(*args)
I18n.t(*args)
end
end
get '/' do
haml :index
end
My locales/en.yml:
en:
welcome: "Welcome!"
When I run rackup and visit the root path of my Sinatra app, I get the following:
I18n::InvalidLocale at /
"en-US" is not a valid locale
file: i18n.rb location: enforce_available_locales! line: 284
I thought that the I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks) would handle this, by not finding en-US and falling back to en (which I have), but apparently not. What am I missing?
Add:
I18n.enforce_available_locales = false
Is this the correct way of handling Redis connection pooling with Sinatra Synchrony?
My gemfile looks like this:
gem 'sinatra-synchrony'
gem 'hiredis'
gem 'redis'
The sinatra server files use the classic style approach, and generally look like so:
require 'sinatra'
require 'sinatra/synchrony'
require 'redis/connection/hiredis'
require 'redis/connection/synchrony'
require 'redis'
redis = EventMachine::Synchrony::ConnectionPool.new(size: 5) do
Redis.new(path: '/tmp/redis.sock')
end
get / do
# lots of redis reads and writes
end
I then launch multiple instances of the same server application, each under a different port, and use nginx to load balance between them.
Is this the proper solution for connection pooling Redis with Sinatra servers?
Here is a working example, I removed sinatra/sinatra because I don't feel it is needed and I couldn't make it works:
Gemfile:
source :rubygems
gem 'thin'
gem 'rack-fiber_pool'
gem 'hiredis'
gem 'sinatra'
gem 'em-synchrony'
gem 'redis'
config.ru:
require 'rubygems'
require 'bundler/setup'
require 'sinatra/base'
require 'redis/connection/synchrony'
require 'redis'
require 'rack/fiber_pool'
class App < Sinatra::Base
set :template_path, '/tmp'
def initialize
super
#redis = EventMachine::Synchrony::ConnectionPool.new(size: 2) do
Redis.new
end
end
get '/' do
#redis.multi do |r|
r.set('v', "value2")
r.set('v2', '43')
end
#redis.get('v')
end
end
use Rack::FiberPool
use Rack::CommonLogger
run App
And run it with (in the same folder):
bundle
bundle exec thin start
In a real application you would remove the application code from the config.ru file and add a require but at least it gives you a start :)
Starting a basic Sinatra app. It doesn't seem to be using my layout template. If I put garbage in my layout.haml, I get the Sinatra 500 error page about it not being a properly formed haml file. Running Ruby 1.9.2. on Windows with the gem of Sinatra, Haml, and Rack installed this evening.
App Code:
require 'rubygems'
require 'sinatra'
require 'haml'
set :haml, :format => :html5
get '/' do
"Hello world, it's #{Time.now} at the server!"
end
App's Location / views / layout.haml
%html
%body
= yield
Source of Generated "http://localhost:4567/" Page
Hello world, it's 2011-11-05 02:25:48 -0400 at the server!
^Notice the lack of my layout.
For this purpose you have to say your template engine in action, something like this:
app code:
require 'sinatra'
require 'haml'
get '/' do
haml :hello
end
views/hello.haml:
%p= "Hello world, it's #{Time.now} at the server!"
views/layout.haml:
%html
%body
= yield
I have correctly (or prbably not) installed passenger on apache 2. Rack works, but sinatra keeps giving 404's.
Here is what works:
config.ru:
#app = proc do |env|
return [200, { "Content-Type" => "text/html" }, "hello <b>world</b>"]
end
run app
Here is what works too:
Running the app.rb (see below) with ruby app.rb and then looking at localhost:4567/about and /
restarting the app, gives me a correct hello world. w00t.
But then there is the sinatra entering the building:
config.ru
require 'rubygems'
require 'sinatra'
root_dir = File.dirname(__FILE__)
set :environment, ENV['RACK_ENV'].to_sym
set :root, root_dir
set :app_file, File.join(root_dir, 'app.rb')
disable :run
run Sinatra::Application
and an app.rb
require 'rubygems'
require 'sinatra'
get '/' do
"Hallo wereld!"
end
get '/about' do
"Hello world, it's #{Time.now} at the server!"
end
This keeps giving 404s.
/var/logs/apache2/error.log lists these correctly as "404" with something that worries me:
83.XXXXXXXXX - - [30/May/2010 16:06:52] "GET /about " 404 18 0.0007
83.XXXXXXXXX - - [30/May/2010 16:06:56] "GET / " 404 18 0.0007
The thing that worried me, is the space after the / and the /about. Would apache or sinatra go looking for /[space], like /%20?
If anyone knows what this problem relates to, maybe a known bug (that I could not find) or a known gotcha?
Maybe I am just being stupid and getting "it all wrong?"
Otherwise any hints on where to get, read or log more developers data on a running rack, sinatra or passenger app would be helpfull too: to see what sinatra is looking for, for example.
Some other information:
Running ubuntu 9.04, apache2-mm-prefork (deb), mod_php5, ruby 1.8.7, passenger 2.2.11, sinatra 1.0
You are not loading the routes in app.rb. To do this, replace require 'sinatra' with require File.join(File.dirname(__FILE__), 'app.rb') in config.ru.
root_dir = File.dirname(__FILE__)
app_file = File.join(root_dir, 'app.rb')
require app_file
set :environment, ENV['RACK_ENV'].to_sym
set :root, root_dir
set :app_file, app_file
disable :run
run Sinatra::Application
set :app_file won't load them for you.
Just substitute the require sinatra with a require 'app' and you're set to go.