-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Change webserver to puma and adapt command line interface #677
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,5 @@ | |
*.gem | ||
coverage/ | ||
log/ | ||
tmp/ | ||
.ruby-version | ||
history.yml |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,5 +3,6 @@ rvm: | |
- 2.3.0 | ||
- 2.2.4 | ||
- 2.1.8 | ||
|
||
- jruby-19mode | ||
- jruby-9.0.4.0 | ||
script: "rake test" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,12 @@ | ||
require 'sinatra' | ||
require 'sprockets' | ||
require 'sinatra/content_for' | ||
require 'rufus/scheduler' | ||
require 'coffee-script' | ||
require 'sass' | ||
require 'json' | ||
require 'rufus/scheduler' | ||
require 'sass' | ||
require 'sinatra' | ||
require 'sinatra/content_for' | ||
require 'sinatra/streaming' | ||
require 'sprockets' | ||
require 'yaml' | ||
require 'thin' | ||
|
||
SCHEDULER = Rufus::Scheduler.new | ||
|
||
|
@@ -34,7 +34,7 @@ def authenticated?(token) | |
set :sprockets, Sprockets::Environment.new(settings.root) | ||
set :assets_prefix, '/assets' | ||
set :digest_assets, false | ||
set server: 'thin', connections: [], history_file: 'history.yml' | ||
set server: 'puma', connections: [], history_file: 'history.yml' | ||
set :public_folder, File.join(settings.root, 'public') | ||
set :views, File.join(settings.root, 'dashboards') | ||
set :default_dashboard, nil | ||
|
@@ -70,13 +70,23 @@ def authenticated?(token) | |
redirect "/" + dashboard | ||
end | ||
|
||
|
||
get '/events', provides: 'text/event-stream' do | ||
protected! | ||
response.headers['X-Accel-Buffering'] = 'no' # Disable buffering for nginx | ||
stream :keep_open do |out| | ||
settings.connections << out | ||
stream do |out| | ||
out << latest_events | ||
out.callback { settings.connections.delete(out) } | ||
settings.connections << connection = {out: out, mutex: Mutex.new, terminated: false} | ||
terminated = false | ||
|
||
loop do | ||
connection[:mutex].synchronize do | ||
terminated = true if connection[:terminated] | ||
end | ||
break if terminated | ||
end | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you guys explain this section a bit more? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Each request gets a thread in the thread pool until Puma hits the max and multiplexes the threads. The loop is basically just "keep the SSE request open until marked as terminated". The connection is marked as terminated in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's no way to keep alive a connection without doing an idle loop? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think so. I am not sure, but I think this is because Sinatra doesn't properly implement Rack hijack. The while loop stuff comes from this: http://tenderlovemaking.com/2012/07/30/is-it-live.html There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The idea that Sinatra doesn't implement rack hijack properly comes from smart dudes comments here: sinatra/sinatra#1035 (comment) But most of it is over my head. |
||
settings.connections.delete(connection) | ||
end | ||
end | ||
|
||
|
@@ -123,22 +133,23 @@ def authenticated?(token) | |
end | ||
end | ||
|
||
Thin::Server.class_eval do | ||
def stop_with_connection_closing | ||
Sinatra::Application.settings.connections.dup.each(&:close) | ||
stop_without_connection_closing | ||
end | ||
|
||
alias_method :stop_without_connection_closing, :stop | ||
alias_method :stop, :stop_with_connection_closing | ||
end | ||
|
||
def send_event(id, body, target=nil) | ||
body[:id] = id | ||
body[:updatedAt] ||= Time.now.to_i | ||
event = format_event(body.to_json, target) | ||
Sinatra::Application.settings.history[id] = event unless target == 'dashboards' | ||
Sinatra::Application.settings.connections.each { |out| out << event } | ||
Sinatra::Application.settings.connections.each do |connection| | ||
connection[:mutex].synchronize do | ||
begin | ||
connection[:out] << event unless connection[:out].closed? | ||
rescue Puma::ConnectionError | ||
connection[:terminated] = true | ||
rescue Exception => e | ||
connection[:terminated] = true | ||
puts e | ||
end | ||
end | ||
end | ||
end | ||
|
||
def format_event(body, name=nil) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
# For a complete list of puma configuration parameters, please see | ||
# https://github.com/puma/puma | ||
|
||
# Puma can serve each request in a thread from an internal thread pool. | ||
# The `threads` method setting takes two numbers a minimum and maximum. | ||
# Any libraries that use thread pools should be configured to match | ||
# the maximum value specified for Puma. Default is set to 5 threads for minimum | ||
# and maximum. | ||
# | ||
threads_count = ENV.fetch("PUMA_MAX_THREADS") { 5 }.to_i | ||
threads threads_count, threads_count | ||
|
||
# Specifies the `port` that Puma will listen on to receive requests, default is 2020. | ||
# | ||
port ENV.fetch("DASHING_PORT") { 3030 } | ||
|
||
# Specifies the `environment` that Puma will run in. | ||
# | ||
environment ENV.fetch("RACK_ENV") { "production" } | ||
|
||
# Daemonize the server into the background. Highly suggest that | ||
# this be combined with "pidfile" and "stdout_redirect". | ||
# | ||
# The default is "false". | ||
# | ||
daemonize ENV.fetch("DAEMONIZE") { false } | ||
|
||
# Store the pid of the server in the file at "path". | ||
# | ||
pidfile './tmp/pids/puma.pid' | ||
|
||
# Use "path" as the file to store the server info state. This is | ||
# used by "pumactl" to query and control the server. | ||
# | ||
state_path './tmp/pids/puma.state' | ||
|
||
# Redirect STDOUT and STDERR to files specified. The 3rd parameter | ||
# ("append") specifies whether the output is appended, the default is | ||
# "false". | ||
# | ||
# stdout_redirect '/u/apps/lolcat/log/stdout', '/u/apps/lolcat/log/stderr' | ||
# stdout_redirect '/u/apps/lolcat/log/stdout', '/u/apps/lolcat/log/stderr', true |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
.empty_directory |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Each connection gets its own Mutex?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it signifies the
out
resource which we are injecting events into insidesend_event
.