airbrake config for heroku+rails - ruby-on-rails

I'm trying to configure airbrake, but can't figure it out. What I wanna achieve is not getting errors from development and test envs only from production.
With the following setup though, I'm getting all the 3 types of error messages as they were occurred in production. So production error sends production error notification but development/test error also sends production error notification.
How can I configure it properly?
# Configures the environment the application is running in. Helps the Airbrake
# dashboard to distinguish between exceptions occurring in different
# environments. By default, it's not set.
# NOTE: This option must be set in order to make the 'ignore_environments'
# option work.
# https://github.com/airbrake/airbrake-ruby#environment
c.environment = :production
# Setting this option allows Airbrake to filter exceptions occurring in
# unwanted environments such as :test. By default, it is equal to an empty
# Array, which means Airbrake Ruby sends exceptions occurring in all
# environments.
# NOTE: This option *does not* work if you don't set the 'environment' option.
# https://github.com/airbrake/airbrake-ruby#ignore_environments
c.ignore_environments = %w(test, development)

You configure your ignored environments like this:
c.ignore_environments = %w(test, development)
# Which is equivalent to:
c.ignore_environments = ['test,', 'development']
The correct way to configure this option is this:
c.ignore_environments = %w(test development)
# Which is equivalent to:
c.ignore_environments = ['test', 'development']
If you use Ruby's %w syntax for arrays, you don't want to use commas.
Another potential issue is that you specify:
c.environment = :production
It will be more robust to use a String (instead of a Symbol) or Rails.env here.
c.environment = Rails.env

Related

Multithreading in Rails: Circular dependency detected while autoloading constant

I have a Rails app in which I have a Rake task that uses multithreading functions supplied by the concurrent-ruby gem.
From time to time I encounter Circular dependency detected while autoloading constant errors.
After Googling for a bit I found this to be related to using threading in combination with loading Rails constants.
I stumbled upon the following GitHub issues: https://github.com/ruby-concurrency/concurrent-ruby/issues/585 and https://github.com/rails/rails/issues/26847
As explained here you need to wrap any code that is called from a new thread in a Rails.application.reloader.wrap do or Rails.application.executor.wrap do block, which is what I did. However, this leads to deadlock.
The recommendation is then to use ActiveSupport::Dependencies.interlock.permit_concurrent_loads to wrap another blocking call on the main thread. However, I am unsure which code I should wrap with this.
Here's what I tried, however this still leads to a deadlock:
#beanstalk = Beaneater.new("#{ENV.fetch("HOST", "host")}:#{ENV.fetch("BEANSTALK_PORT", "11300")}")
tube_name = ENV.fetch("BEANSTALK_QUEUE_NAME", "queue")
pool = Concurrent::FixedThreadPool.new(Concurrent.processor_count * 2)
# Process jobs from tube, the body of this block gets executed on each message received
#beanstalk.jobs.register(tube_name) do |job|
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
#logger.info "Received job: #{job.id}"
Concurrent::Future.execute(executor: pool) do
Rails.application.reloader.wrap do
# Stuff that references Rails constants etc
process_beanstalk_message(job.body)
end
end
end
end
#beanstalk.jobs.process!(reserve_timeout: 10)
Can anyone shed a light as to how I should solve this? The odd thing is I encounter this in production while other information on this topic seems to imply it should normally only occur in development.
In production I use the following settings:
config.eager_load = true
config.cache_classes = true.
Autoload paths for all environments are Rails default plus two specific folders ("models/validators" & "jobs/concerns").
eager_load_paths is not modified or set in any of my configs so must be equal to the Rails default.
I am using Rails 5 so enable_dependency_loading should equal to false in production.
You likely need to change your eager_load_paths to include the path to the classes or modules that are raising the errors. eager_load_paths is documented in the Rails Guides.
The problem you're running into is that Rails is not loading these constants when the app starts; it automatically loads them when they are called by some other piece of code. In a multithreaded Rails app, two threads may have a race condition when they try to load these constants.
Telling Rails to eagerly load these constants means they will be loaded once when the Rails app is started. It's not enough to say eager_load = true; you have to specify the paths to the class or module definitions as well. In the Rails application configuration, this is an Array under eager_load_paths. For example, to eager load ActiveJob classes:
config.eager_load_paths += ["#{config.root}/app/jobs"]
Or to load a custom module from lib/:
config.eager_load_paths += ["#{config.root}/lib/custom_module"]
Changing your eager load settings will affect the behavior of Rails. For example, in the Rails development environment, you're probably used to running rails server once, and every time you reload one of the endpoints it will reflect any changes to code you've made. That will not work with config.eager_load = true, because the classes are loaded once, at startup. Therefore, you will typically only change your eager_load settings for production.
Update
You can check your existing eager_load_paths from the rails console. For example, these are the default values for a new Rails 5 app. As you can see, it does not load app/**/*.rb; it loads the specific paths that Rails is expected to know about.
Rails.application.config.eager_load_paths
=> ["/app/assets",
"/app/channels",
"/app/controllers",
"/app/controllers/concerns",
"/app/helpers",
"/app/jobs",
"/app/mailers",
"/app/models",
"/app/models/concerns"]
In my gems (i.e., in plezi and iodine) I solve this with if statements, mostly.
You'll find code such as:
require 'uri' unless defined?(::URI)
or
begin
require 'rack/handler' unless defined?(Rack::Handler)
Rack::Handler::WEBrick = ::Iodine::Rack # Rack::Handler.get(:iodine)
rescue Exception
end
I used these snippets because of Circular dependency detected warnings and errors.
I don't know if this helps, but I thought you might want to try it.
I had this issue while trying out two gems that handles parallel processing;
pmap gem
parallel gem
For pmap I kept getting an error related to Celluloid::TaskTerminated and for parallel I was getting a Circular dependency detected while autoloading constant for when I ran it with more than 1 thread. I knew this issue was related to how my classes and modules were eager loading and race to be placed on a thread. I try enabling both of the configs to true config.cache_classes = true and config.eager_load = true in the development env and that did the trick for me.

Capybara server & browser error with no trace on server

For some reason one of my cucumber tests seem to fail both on the poltergeist driver and from the rails server.
I am getting a full trace on the browser crash but almost nothing on the server side.
When I open the Capybara screenshot I just see
Internal Server Error
undefined method name for nil:NilClass
When I tail the test.log
Completed 500 Internal Server Error in 0ms (Elasticsearch: 0.0ms)
(And no trace)
I have tried
to set config.action_dispatch.show_exceptions = true
the b flag (but it's only showing the detailed trace for the Capybara error
(my config level is set to :debug already in my environment file)
How can I get the full backtrace on the server side ?
EDIT
Capybara 2.13.0
Rails 5.0.2
everything commented in backtrace_silencers
I got something from this answer !
So the solution was to allow rescuing the exception in ActionController::Base. In my env file I had the following lines that were misleading
# There are two ways to allow Rails to rescue exceptions:
#
# 1) Tag your scenario (or feature) with #allow-rescue
#
# 2) Set the value below to true. Beware that doing this globally is not
# recommended as it will mask a lot of errors for you!
#
ActionController::Base.allow_rescue = false
And by adding the #allow-rescue tag I got more comprehensive error trace showing in my test.log, along with a frontend error view
If you (like me) do not use Cucumber but Capybara this answer might help you, too.
In config/environments/test.rb set
config.action_dispatch.show_exceptions = true

Set Rails Variable to Different Values for Different Capistrano Environments

I have a rails app which is set up to deploy with Capistrano to one of two different servers (depending on which the user chooses to deploy to). I want to create an environment variable for the rails app which changes depending on which server the website is deployed to.
In my Capistrano deploy (config/deploy.rb) file, I have a variable "stages" that has the two options for the user to deploy to:
set :stages, %w(production staging)
I have tried to use this variable in an if statement in my environment (config/environment.rb) file to set the variable like so:
if (:stages == "staging")
ENV['GLOBAL_EMAIL'] = "email1#domain.com"
else
ENV['GLOBAL_EMAIL'] = "email2#domain.com"
end
However, when I test this, rails fails to render #{ENV['GLOBAL_EMAIL']} (as far as I can tell because the variable is not set or reachable.
My question is if there is a reason that :stages is not reachable, and also if there is a way/better way to set the variable according to the environment?
Note that even though one is called staging and one is called production, both environments deploy the production environment of rails (not test and production environments of rails), thus I cannot do a test to see which environment rails is running to then set the variable.
For starters you are trying to equate a symbol with a string, which will always return false.
Also within capistrano, to get the environment your deploying in you want the stage variable. This variable is only available after loading and not when the file is read by ruby. What this means is that you need to provide a block that gets lazy loaded. The problem is that these are evaluated in the context of setting a local variable such as deploy_to.
set(:deploy_to) { "/var/www/#{application}/#{stage}" }
This is a common setup within my deploy scripts where staging and production are deployed to the same server.
You could possibly try something like:
set(:global_email) do
if stage == 'production'
ENV['GLOBAL_EMAIL'] = 'email1#example.com'
else
ENV['GLOBAL_EMAIL'] = 'email2#example.com'
end
end
Or another way of handling this is to use the deploy stage specific files.
# config/deploy/production.rb
ENV['GLOBAL_EMAIL'] = 'email1#example.com'
# config/deploy/staging.rb
ENV['GLOBAL_EMAIL'] = 'email2#example.com'
Update
I hadn't noticed the question mentioned rendering the value in Rails. This of course has nothing to do with Rails, nor is anything set in a Capistrano config file available when Rails is initialized since capistrano should really be only available in development environments.
A proper way to do this would be using a rails initalizer and setting the variable when Rails boots up.
# config/initializer/global_email.rb
if Rails.env.production?
GLOBAL_EMAIL = 'email1#example.com'
else
GLOBAL_EMAIL = 'email2#example.com'
end
The final solution I ended up with was to create a file external from my Capistrano deploy (for instance in /home/[user]/.var/.emails) on each server where each file contains just the desired email (e.g. email1#domain.com). Then in environments.rb:
ENV['GLOBAL_EMAIL'] = begin IO.read("/home/[user]/.vars/.email") rescue "" end

How do I turn off Rails SQL logging in test?

For some reason (probably an updated gem) Rails is logging all my SQL commands now. I run autotest and they are being spammed during tests also. How do I turn it off?
I tried add this to config/environments/test.rb but it didn't work. logger was already nil.
# ActiveRecord::Base.logger = nil
# ActiveRecord::Base.logger.level = 1
Rails 4.0.0
Ok I found it. This worked:
config.after_initialize do
ActiveRecord::Base.logger = nil
end
Another thing you can do is call this code at runtime, it doesn't need to be in a config file.
For example, if you put in your specific test case
# test/functionals/application_controller_test.rb for example
ActiveRecord::Base.logger = nil
It would work just as well, and this way you can toggle it at runtime. Useful if you only want to stifle a few lines of code or a block.
In case someone wants to actually knock out SQL statement logging (without changing logging level, and while keeping the logging from their AR models):
The line that writes to the log (in Rails 3.2.16, anyway) is the call to 'debug' in lib/active_record/log_subscriber.rb:50.
That debug method is defined by ActiveSupport::LogSubscriber.
So we can knock out the logging by overwriting it like so:
module ActiveSupport
class LogSubscriber
def debug(*args, &block)
end
end
end

How to disable ActionMailer in Development?

sometimes when I am developing, I do not have an internet connection. This results in an error wherever my app is supposed to send an email:
getaddrinfo: nodename nor servname provided, or not known
Is there a simple and quick way where i can change a config value to make ActionMailer just not try to actually send out an email and not throw an error? Maybe something thats scoped to the development environment. Or some other way I can avoid the error being thrown and my code passing wherever I call the actionmailer deliver?
I'm using Rails 3.1
It's common practice to just let Rails ignore the mail errors. In your config/environments/development.rb file add, uncomment or modify:
# Don't care if the mailer can't send
config.action_mailer.raise_delivery_errors = false
You can also set this:
config.action_mailer.perform_deliveries = false
See the documentation here http://edgeguides.rubyonrails.org/action_mailer_basics.html#action-mailer-configuration
You can also set the delivery method to :test, but I have not actually tried that
config.action_mailer.delivery_method = :test
If you want to disable mail deliveries after your rails app has been initialized (while creating sample data, during migrations, etc.):
ActionMailer::Base.perform_deliveries = false

Resources