Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drop thin support #1627

Merged
merged 7 commits into from Aug 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion Gemfile
Expand Up @@ -41,7 +41,8 @@ if RUBY_ENGINE == "ruby"
gem 'puma'
gem 'yajl-ruby'
gem 'nokogiri'
gem 'puma'
gem 'rainbows'
gem 'eventmachine'
gem 'slim', '~> 2.0'
gem 'coffee-script', '>= 2.0'
gem 'rdoc'
Expand Down
83 changes: 54 additions & 29 deletions README.md
Expand Up @@ -34,7 +34,7 @@ The code you changed will not take effect until you restart the server.
Please restart the server every time you change or use
[sinatra/reloader](http://www.sinatrarb.com/contrib/reloader).

It is recommended to also run `gem install thin`, which Sinatra will
It is recommended to also run `gem install puma`, which Sinatra will
pick up if available.

## Table of Contents
Expand Down Expand Up @@ -1685,36 +1685,53 @@ to `stream` finishes executing. Streaming does not work at all with Shotgun.

If the optional parameter is set to `keep_open`, it will not call `close` on
the stream object, allowing you to close it at any later point in the
execution flow. This only works on evented servers, like Thin and Rainbows.
execution flow. This only works on evented servers, like Rainbows.
Other servers will still close the stream:

```ruby
namusyaka marked this conversation as resolved.
Show resolved Hide resolved
# long polling

set :server, :thin
connections = []
# config.ru
require 'sinatra/base'

get '/subscribe' do
# register a client's interest in server events
stream(:keep_open) do |out|
connections << out
# purge dead connections
connections.reject!(&:closed?)
class App < Sinatra::Base
connections = []

get '/subscribe' do
# register a client's interest in server events
stream(:keep_open) do |out|
connections << out
# purge dead connections
connections.reject!(&:closed?)
end
end
end

post '/:message' do
connections.each do |out|
# notify client that a new message has arrived
out << params['message'] << "\n"
post '/:message' do
connections.each do |out|
# notify client that a new message has arrived
out << params['message'] << "\n"

# indicate client to connect again
out.close
# indicate client to connect again
out.close
end

# acknowledge
"message received"
end
end

run App
```

# acknowledge
"message received"
```ruby
# rainbows.conf
Rainbows! do
use :EventMachine
end
````

Run:

```shell
rainbows -c rainbows.conf
```

It's also possible for the client to close the connection when trying to
Expand Down Expand Up @@ -2377,7 +2394,7 @@ set :protection, :session => true
If you are using a WEBrick web server, presumably for your development
environment, you can pass a hash of options to <tt>server_settings</tt>,
such as <tt>SSLEnable</tt> or <tt>SSLVerifyClient</tt>. However, web
servers such as Puma and Thin do not support this, so you can set
servers such as Puma do not support this, so you can set
<tt>server_settings</tt> by defining it as a method when you call
<tt>configure</tt>.
</dd>
Expand Down Expand Up @@ -2428,7 +2445,7 @@ set :protection, :session => true

<dt>threaded</dt>
<dd>
If set to <tt>true</tt>, will tell Thin to use
If set to <tt>true</tt>, will tell server to use
<tt>EventMachine.defer</tt> for processing the request.
</dd>

Expand Down Expand Up @@ -3017,7 +3034,7 @@ Options are:
-p # set the port (default is 4567)
-o # set the host (default is 0.0.0.0)
-e # set the environment (default is development)
-s # specify rack server/handler (default is thin)
-s # specify rack server/handler (default is puma)
-q # turn on quiet mode for server (default is off)
-x # turn on the mutex lock (default is off)
```
Expand All @@ -3029,15 +3046,15 @@ _Paraphrasing from
by Konstantin_

Sinatra doesn't impose any concurrency model, but leaves that to the
underlying Rack handler (server) like Thin, Puma or WEBrick. Sinatra
underlying Rack handler (server) like Puma or WEBrick. Sinatra
itself is thread-safe, so there won't be any problem if the Rack handler
uses a threaded model of concurrency. This would mean that when starting
the server, you'd have to specify the correct invocation method for the
specific Rack handler. The following example is a demonstration of how
to start a multi-threaded Thin server:
to start a multi-threaded Rainbows server:

```ruby
# app.rb
# config.ru

require 'sinatra/base'

Expand All @@ -3047,14 +3064,22 @@ class App < Sinatra::Base
end
end

App.run!
run App
```

```ruby
# rainbows.conf

# Rainbows configurator is based on Unicorn.
Rainbows! do
use :ThreadSpawn
end
namusyaka marked this conversation as resolved.
Show resolved Hide resolved
```

To start the server, the command would be:

```shell
thin --threaded start
rainbows -c rainbows.conf
```

## Requirement
Expand Down
2 changes: 1 addition & 1 deletion examples/chat.rb
@@ -1,7 +1,7 @@
#!/usr/bin/env ruby -I ../lib -I lib
# coding: utf-8
require 'sinatra'
set :server, 'thin'
set :server, 'puma'
connections = []

get '/' do
Expand Down
3 changes: 3 additions & 0 deletions examples/rainbows.conf
@@ -0,0 +1,3 @@
Rainbows! do
use :EventMachine
end
8 changes: 4 additions & 4 deletions examples/stream.ru
Expand Up @@ -2,10 +2,10 @@
#
# run *one* of these:
#
# rackup -s mongrel stream.ru # gem install mongrel
# thin -R stream.ru start # gem install thin
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please copy test/integration/rainbows.conf here and add rainbows -c rainbows.conf stream.ru.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed 7a96472

# unicorn stream.ru # gem install unicorn
# puma stream.ru # gem install puma
# rackup -s mongrel stream.ru # gem install mongrel
# unicorn stream.ru # gem install unicorn
# puma stream.ru # gem install puma
# rainbows -c rainbows.conf stream.ru # gem install rainbows eventmachine

require 'sinatra/base'

Expand Down
10 changes: 4 additions & 6 deletions lib/sinatra/base.rb
Expand Up @@ -206,7 +206,7 @@ def drop_body?
end
end

# Some Rack handlers (Thin, Rainbows!) implement an extended body object protocol, however,
# Some Rack handlers (Rainbows!) implement an extended body object protocol, however,
# some middleware (namely Rack::Lint) will break it by not mirroring the methods in question.
# This middleware will detect an extended body object and will make sure it reaches the
# handler directly. We do this here, so our middleware and middleware set up by the app will
Expand Down Expand Up @@ -473,7 +473,7 @@ def closed?
#
# The close parameter specifies whether Stream#close should be called
# after the block has been executed. This is only relevant for evented
# servers like Thin or Rainbows.
# servers like Rainbows.
def stream(keep_open = false)
scheduler = env['async.callback'] ? EventMachine : Stream
current = @params.dup
Expand Down Expand Up @@ -1475,8 +1475,7 @@ def use(middleware, *args, &block)
# Stop the self-hosted server if running.
def quit!
return unless running?
# Use Thin's hard #stop! if available, otherwise just #stop.
running_server.respond_to?(:stop!) ? running_server.stop! : running_server.stop
running_server.stop
$stderr.puts "== Sinatra has ended his set (crowd applauds)" unless suppress_messages?
set :running_server, nil
set :handler_name, nil
Expand All @@ -1485,7 +1484,7 @@ def quit!
alias_method :stop!, :quit!

# Run the Sinatra app as a self-hosted server using
# Thin, Puma, Mongrel, or WEBrick (in that order). If given a block, will call
# Puma, Mongrel, or WEBrick (in that order). If given a block, will call
# with the constructed handler once we have taken the stage.
def run!(options = {}, &block)
return if running?
Expand Down Expand Up @@ -1849,7 +1848,6 @@ class << self
server.unshift 'reel'
server.unshift 'puma'
server.unshift 'mongrel' if ruby_engine.nil?
server.unshift 'thin' if ruby_engine != 'jruby'
server.unshift 'trinidad' if ruby_engine == 'jruby'
namusyaka marked this conversation as resolved.
Show resolved Hide resolved
end

Expand Down
2 changes: 1 addition & 1 deletion lib/sinatra/main.rb
Expand Up @@ -5,7 +5,7 @@ module Sinatra
require 'optparse'
parser = OptionParser.new { |op|
op.on('-p port', 'set the port (default is 4567)') { |val| ParamsConfig[:port] = Integer(val) }
op.on('-s server', 'specify rack server/handler (default is thin)') { |val| ParamsConfig[:server] = val }
op.on('-s server', 'specify rack server/handler (default is puma)') { |val| ParamsConfig[:server] = val }
op.on('-q', 'turn on quiet mode (default is off)') { ParamsConfig[:quiet] = true }
op.on('-x', 'turn on the mutex lock (default is off)') { ParamsConfig[:lock] = true }
op.on('-e env', 'set the environment (default is development)') do |val|
Expand Down
2 changes: 2 additions & 0 deletions test/integration/app.rb
@@ -1,6 +1,8 @@
$stderr.puts "loading"
require 'sinatra'

require_relative 'rainbows' if RUBY_ENGINE == 'ruby'

configure do
set :foo, :bar
end
Expand Down
3 changes: 3 additions & 0 deletions test/integration/rainbows.conf
@@ -0,0 +1,3 @@
Rainbows! do
use :EventMachine
end
20 changes: 20 additions & 0 deletions test/integration/rainbows.rb
@@ -0,0 +1,20 @@
require 'rainbows'

module Rack
module Handler
class Rainbows
def self.run(app, **options)
rainbows_options = {
listeners: ["#{options[:Host]}:#{options[:Port]}"],
worker_processes: 1,
timeout: 30,
config_file: ::File.expand_path('../rainbows.conf', __FILE__),
}

::Rainbows::HttpServer.new(app, rainbows_options).start.join
end
end

register "rainbows", "Rack::Handler::Rainbows"
end
end
14 changes: 14 additions & 0 deletions test/integration_async_helper.rb
@@ -0,0 +1,14 @@
require File.expand_path('../integration_helper', __FILE__)

module IntegrationAsyncHelper
def it(message, &block)
base_port = 5100 + Process.pid % 100

%w(rainbows).each_with_index do |server_name, index|
server = IntegrationHelper::BaseServer.new(server_name, base_port + index)
next unless server.installed?

super("with #{server.name}: #{message}") { server.run_test(self, &block) }
end
end
end
40 changes: 40 additions & 0 deletions test/integration_async_test.rb
@@ -0,0 +1,40 @@
require File.expand_path('../helper', __FILE__)
require File.expand_path('../integration_async_helper', __FILE__)

# These tests are like integration_test, but they test asynchronous streaming.
class IntegrationAsyncTest < Minitest::Test
extend IntegrationAsyncHelper
attr_accessor :server

it 'streams async' do
Timeout.timeout(3) do
chunks = []
server.get_stream '/async' do |chunk|
next if chunk.empty?
chunks << chunk
case chunk
when "hi!" then server.get "/send?msg=hello"
when "hello" then server.get "/send?close=1"
end
end

assert_equal ['hi!', 'hello'], chunks
end
end

it 'streams async from subclass' do
Timeout.timeout(3) do
chunks = []
server.get_stream '/subclass/async' do |chunk|
next if chunk.empty?
chunks << chunk
case chunk
when "hi!" then server.get "/subclass/send?msg=hello"
when "hello" then server.get "/subclass/send?close=1"
end
end

assert_equal ['hi!', 'hello'], chunks
end
end
end
6 changes: 3 additions & 3 deletions test/integration_helper.rb
Expand Up @@ -61,7 +61,7 @@ def command
file, dir = RbConfig::CONFIG.values_at('ruby_install_name', 'bindir')
cmd << File.expand_path(file, dir).inspect
end
cmd << "-w" unless thin? || net_http_server?
cmd << "-w" unless net_http_server?
cmd << "-I" << File.expand_path('../../lib', __FILE__).inspect
cmd << app_file.inspect << '-s' << server << '-o' << '127.0.0.1' << '-p' << port
cmd << "-e" << environment.to_s << '2>&1'
Expand All @@ -73,8 +73,8 @@ def webrick?
name.to_s == "webrick"
end

def thin?
name.to_s == "thin"
def rainbows?
name.to_s == "rainbows"
end

def puma?
Expand Down