-
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 | ||
|
|
||
|
Member
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?
Contributor
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
Member
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?
Contributor
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
Contributor
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
outresource which we are injecting events into insidesend_event.