Tag: exceptions
(page 1 of 2)

Note: If you’re using old Errbit version (0.2.0, 0.4.0) and an old Airbrake version (v4) please refer to this manual to make it work with self-signed certificates.

Having an error catcher like Errbit behind SSL is generally a good idea. Especially when Errbit is hosted on a different server than you application (for example when you manage multiple apps with one Errbit instance). In many cases you will have a self-signed certificate (why would you pay for a cert for internal tool). If you try to use it with Airbrake, you will see following error:

Luckily, Airbrake notifier is written pretty well, so hacking it (and disabling per request SSL certificate verification) is not hard at all. Here’s a full code you need to place in config/initializers/errbit.rb to make it work:

module Patches
module Airbrake
module SyncSender
def build_https(uri)
super.tap do |req|
req.verify_mode = OpenSSL::SSL::VERIFY_NONE
end
end
end
end
end
Airbrake::SyncSender.prepend(::Patches::Airbrake::SyncSender)

After that (and configuring Airbrake notifier), you can test it out like this:

I’ve seen also few cases, when exceptions parameters were used to pass objects that the programmer was later on working with!

As you can see, the whole flow of this piece of code is handled with exceptions. In this post I will focus on a performance reason why it is bad, (but if you’re interested in how to refactor code like this, at the end of this post you will find some external links about that. That’s why I’ve prepared a simple benchmark

require 'benchmark'
elements = [0, 1]
big_ar = (1..10000).to_a
TIMES = 100000
Benchmark.bmbm do |x|
x.report('break') do
TIMES.times do
elements.each do |i|
break
end
end
end
x.report('catch throw') do
TIMES.times do
catch(:benchmarking) do
elements.each do |i|
throw(:benchmarking)
end
end
end
end
x.report('catch throw heavy') do
TIMES.times do
catch(:benchmarking) do
elements.each do |i|
throw(:benchmarking, big_ar)
end
end
end
end
x.report('fail') do
TIMES.times do
begin
elements.each do |i|
fail StandardError
end
rescue
end
end
end
x.report('fail heavy') do
TIMES.times do
begin
elements.each do |i|
fail StandardError, big_ar, {}
end
rescue
end
end
end
x.report('raise') do
TIMES.times do
begin
elements.each do |i|
raise StandardError
end
rescue
end
end
end
x.report('raise heavy') do
TIMES.times do
begin
elements.each do |i|
raise StandardError, big_ar, {}
end
rescue
end
end
end
end

Catch/throw performance is not influenced by the size of passed attribute – it doesn’t matter if we pass a huge structure or a simple object

Performance of fail and raise is almost equal, for both normal and heavy case

Fail/raise can be up to 12 times slower than break

Fail/raise can be up to 6 times slower than catch/throw

So, from the performance point of view, handling flow with exceptions can be much more expensive than in other ways. Exceptions are heavy because they are exceptions. They aren’t suppose to happen all the time, that’s why the implementers of compilers nor the designers of the language focus on their performance.

Refactoring

If you’ve noticed code like this in your apps, here are some great blog posts on how to fix that: