diff --git a/lib/travis/api/app.rb b/lib/travis/api/app.rb index 42cc85f2..f9690614 100644 --- a/lib/travis/api/app.rb +++ b/lib/travis/api/app.rb @@ -23,6 +23,7 @@ require 'travis/api/instruments' require 'travis/api/v2/http' require 'travis/api/v3' require 'travis/api/app/stack_instrumentation' +require 'travis/api/app/error_handling' # Rack class implementing the HTTP API. # Instances respond to #call. @@ -93,7 +94,7 @@ module Travis::Api end use Travis::Api::App::Cors # if Travis.env == 'development' ??? - use Raven::Rack if Endpoint.production? && Travis.config.sentry.dsn + use Raven::Rack if Travis.env == 'production' || Travis.env == 'staging' use Rack::Protection::PathTraversal use Rack::SSL if Endpoint.production? use ActiveRecord::ConnectionAdapters::ConnectionManagement @@ -157,6 +158,10 @@ module Travis::Api defined? Travis::Console end + def self.use_monitoring? + Travis.env == 'production' || Travis.env == 'staging' + end + def self.setup! setup_travis load_endpoints @@ -170,13 +175,13 @@ module Travis::Api setup_database_connections - if Travis.env == 'production' || Travis.env == 'staging' + if use_monitoring? Sidekiq.configure_client do |config| config.redis = Travis.config.redis.merge(size: 1, namespace: Travis.config.sidekiq.namespace) end end - if (Travis.env == 'production' || Travis.env == 'staging') and not console? + if use_monitoring? and not console? setup_monitoring end end @@ -191,9 +196,7 @@ module Travis::Api end def self.setup_monitoring - Raven.configure do |config| - config.dsn = Travis.config.sentry.dsn - end if Travis.config.sentry.dsn + Travis::Api::App::ErrorHandling.setup Travis::LogSubscriber::ActiveRecordMetrics.attach Travis::Notification.setup(instrumentation: false) diff --git a/lib/travis/api/app/error_handling.rb b/lib/travis/api/app/error_handling.rb new file mode 100644 index 00000000..68e69556 --- /dev/null +++ b/lib/travis/api/app/error_handling.rb @@ -0,0 +1,26 @@ +require 'travis/api/app' + +class Travis::Api::App + class ErrorHandling + + def self.setup + return unless Travis.config.sentry.dsn + queue = ::SizedQueue.new(100) + Thread.new do + loop do + begin + Raven.send queue.pop + rescue Exception => e + puts e.message, e.backtrace + end + end + end + + Raven.configure do |config| + config.async = lambda { |event| queue << event if queue.num_waiting < 100 } + config.dsn = Travis.config.sentry.dsn + end + end + + end +end diff --git a/spec/integration/error_handling_spec.rb b/spec/integration/error_handling_spec.rb new file mode 100644 index 00000000..8e04d1d2 --- /dev/null +++ b/spec/integration/error_handling_spec.rb @@ -0,0 +1,35 @@ +require 'spec_helper' +require 'sentry-raven' + +describe 'Exception' do + + class FixRaven < Struct.new(:app) + def call(env) + requested_at = env['requested_at'] + env['requested_at'] = env['requested_at'].to_s if env.key?('requested_at') + app.call(env) + rescue Exception => e + env['requested_at'] = requested_at + raise e + end + end + + class TestError < StandardError + end + + before do + set_app Raven::Rack.new(FixRaven.new(app)) + Travis.config.sentry.dsn = "test" + Travis::Api::App.setup_monitoring + end + + it 'enques error into a thread' do + error = TestError.new('Konstantin broke all the thingz!') + Travis::Api::App::Endpoint::Repos.any_instance.stubs(:service).raises(error) + Raven.expects(:send).with do |event| + event.message == "#{error.class}: #{error.message}" + end + expect { get "/repos" }.to raise_error(TestError) + sleep 0.1 + end +end