Skip to content

Commit

Permalink
Merge pull request #1627 from rkmathi/rkmathi/drop-thin-support
Browse files Browse the repository at this point in the history
Drop thin support
  • Loading branch information
namusyaka committed Aug 8, 2020
2 parents 103f8ff + 7a96472 commit f57acef
Show file tree
Hide file tree
Showing 15 changed files with 153 additions and 89 deletions.
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
# 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
```

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
# 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'
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

0 comments on commit f57acef

Please sign in to comment.