SlideShare ist ein Scribd-Unternehmen logo
1 von 52
Error Handling in Ruby & Rails
       Simon Maynard - Bugsnag CTO
              @snmaynard
What is Bugsnag?

•   We help developers log and track their errors

•   Ruby was the first language we supported

•   Now support Python, PHP, Javascript, Node.js, iOS, Android & more!

•   Processing millions of errors every day
What is AN ERROR?

An error occurs when code is unable to complete the task asked of it.

  •   Asked to do the impossible
           Account.find(nil)


  •   A mistake in the code
            account = Account.new
            acccount.name #!?
What is AN ERROR?

•   An unexpected case
           case account.type
           when "free" then #
           when "paid" then #
           else
             # Unexpected!
           end

•   Failure of an external element
           # Database down!
           account.save
How to report an error?

•   Raise an exception

    •   Only when the error is truly exceptional

    •   If the error is unexpected, or a sign of bad code

    •   Raising should be unexpected, it’s slow
How to report an error?

•   Return an error value

    •   If its to be expected or part of "normal" operation

def find(id)
  raise InvalidIdError, "#{id} id an invalid id" unless validate_id(id)
  return data[id]
end
Raise Or Fail

•   You can use raise to raise an exception.

•   You can also use fail to raise an exception.

                   def func
                     fail "Not implemented"
                   rescue => e
                     raise unless e.message == "Not implemented"
                   end
Raise Syntax


 raise MyError.new("Something Broke")


is the same as
 raise MyError, "Something Broke"
Raise Syntax


 raise "Something Broke"


is the same as
 raise RuntimeError, "Something Broke"
Raise Syntax


 raise


is the same as
 raise RuntimeError
Raise Syntax


You can also pass a backtrace when raising an exception
 def assert(value)
   raise(RuntimeError, "Something broke", caller) unless value
 end
What does raise actually do?

•   Raise does four things,

    •   Builds an exception object

    •   Sets the backtrace

    •   Sets the global error object ($!)

    •   Starts unwinding the stack
How does raise build the exception?

You might think that raise does this
                         def raise(klass, msg, trace)
                           exception = klass.new(message)
                           # ...
                         end

But actually it does this...
                         def raise(klass, msg, trace)
                           exception = klass.exception(message)
                           # ...
                         end
How does raise build the exception?

•   Exception.exception

    •   The same as Exception.new()

•   Exception#exception

    •   With no arguments, it returns self

    •   With a message, it returns a new exception with the message set
How does raise build the exception?

This means we can implement our own exception methods
          class Account
            def exception(message="Bad Account!")
              ValidationError.new("#{message}: #{self.errors.inspect}")
            end
          end

then we can throw an instance of own object
          raise account unless account.save
Global Error Object
$! contains a reference to the exception currently being raised
   begin
     raise
   rescue
     puts $!.inspect
   end

You can also require “english” to use the slightly more readable
$ERROR_INFO
  require "english"
  begin
    raise
  rescue
    puts $ERROR_INFO.inspect
  end
rescue Syntax

 begin
 rescue MyError => error
 end

will rescue all MyError exceptions
rescue Syntax

 begin
 rescue => error
 end

is the same as
 begin
 rescue StandardError => error
 end
Rescue Syntax

 begin
 rescue
 end

is the same as
 begin
 rescue StandardError
 end
Rescue Syntax


You can also supply a list of classes to rescue
  begin
  rescue MyError, IOError => error
  end
One Line Rescue Syntax


  value = raise rescue "fallback_value"

is the same as
 value = begin
   raise
 rescue
   "fallback_value"
 end
Dynamic rescues
def match_message(regex)
  mod = Module.new
  (class << mod; self; end).instance_eval do
    define_method(:===) do |e|
      regex === e.message
    end
  end
  mod
end

begin
  raise "sample message"
rescue match_message(/sample/)
  # Ignore
end
Re-raising exception
 begin
   raise
 rescue
   raise
 end

is the same as
 begin
   raise
 rescue
   raise $!
 end
Raising in rescue

You can also change the exception message before re-raising


                        begin
                          raise
                        rescue => err
                          # Re raise with different message
                          raise err, “Different message”
                        end
Raising in rescue

You can raise in a rescue
                            def func
                              raise
                            rescue
                              raise "totally new exception"
                            end

You lose the context of the real error!

Don’t do this!
Raising in rescue
Instead you can keep a reference to the original exception
                  class MyError < StandardError
                    attr_accessor :original_exception
                    def initialize(msg, original_exception=$!)
                      super(msg)
                      self.original_exception = original_exception
                    end
                  end

                  def func
                    raise
                  rescue
                    raise MyError.new("Something broke")
                  end
Ensure Syntax

Ensure allows you to ensure that code is run, regardless of whether an exception
is raised or not.

                         begin
                           raise unless rand < 0.5
                         ensure
                           # Always run
                         end
ALTERNATIVE Syntax

You can also use these commands without a begin section

                         def func(arg)
                           raise
                         rescue
                           # Deal with exception
                         ensure
                           # Always run
                         end
Ensure Syntax

Be careful with return inside an ensure!


                   def func(arg)
                     raise
                   ensure
                     # This return swallows the exception
                     return 5
                   end
RETRY

You can also easily retry using the retry keyword
                        def func(arg)
                          attempts = 0
                          begin
                            attempts += 1
                            raise
                          rescue
                            retry if attempts < 3
                          end
                        end
exception hierarchy
                                     Exception


NoMemoryError   ScriptError   SignalException    SystemExit   StandardError   fatal

                                 Interrupt
                 LoadError                                    ArgumentError
                SyntaxError                                       IOError
                     ...                                        IndexError
                                                                     ...
Exception hierarchy

For example,
                 while true do
                   begin
                     line = STDIN.gets
                     # heavy processing
                   rescue Exception => e
                     puts "caught exception #{e}! ohnoes!"
                   end
                 end


This program is almost unkillable! Don’t catch Exception!
Exception Hierarchy

You can even prevent an exit call,
                            begin
                              exit(1) # Or abort()
                            rescue Exception
                              puts "Guess again!"
                            end
                            # Continue...




You can’t catch an exit!(1) however...
Raise is a method

•   Raise is just a method on Kernel

•   So we can override it!
Raise is a method

We can add debugging information to each raise
                    module RaiseDebug
                      def raise(*args)
                        super *args
                      rescue Exception
                        puts "Raising exception: #{$!.inspect}"
                        super *args
                      end
                    end
                    class Object
                      include RaiseDebug
                    end
Uncaught Errors

We can use a combination of $! and the ruby exit handler to log uncaught errors
                       at_exit do
                         if $!
                           open('error.log', 'a') do |log_file|
                             error = {
                               timestamp: Time.now.utc,
                               message:   $!.message,
                               trace:     $!.backtrace,
                             }
                             log_file.write(error.to_json)
                           end
                         end
                       end
Throw/Catch

Ruby can also throw, but its not for errors.

Use throw to unwrap the stack in a non-exceptional case, saves you from using
multiple break commands
                        INFINITY = 1.0 / 0.0
                        catch (:done) do
                          1.upto(INFINITY) do |i|
                            1.upto(INFINITY) do |j|
                              if some_condition
                                throw :done
                              end
                            end
                          end
                        end
How does rails deal with exceptions?

When there is an error in your rails app, ideally we want these things to happen

      •   500 page rendered to show the user something went wrong

      •   Error logged with enough information so we can fix it

      •   Rails to continue serving requests
How does rails deal with exceptions?

•   Rails uses a Rack app to process every request.

•   Rack apps have a middleware stack

•   You can easily add your own middleware so you can execute code on every
    request
    config.middleware.use(new_middleware, args)
    config.middleware.insert_before(existing_middleware, new_middleware, args)
    config.middleware.insert_after(existing_middleware, new_middleware, args)
    config.middleware.delete(middleware)
RACK Middleware
 Request           Response


      Middleware 1

      Middleware 2

      Middleware 3

      Middleware 4

           Rails App
Example RACK Middleware

Here is an example of a no-op middleware
                         module OurMiddleware
                           class Rack
                             def initialize(app)
                               @app = app
                             end

                             def call(env)
                               @app.call(env)
                             end
                           end
                         end
Example RACK Middleware

•   Initialize called when rails app starts

•   Takes a single parameter, which is the next middleware in the stack

•   Perform any other initialization for your middleware

                              def initialize(app)
                                @app = app
                              end
Example RACK Middleware

•   Call is called for every request

•   @app.call calls the next middleware in the stack (or your app itself)


                             def call(env)
                               response = @app.call(env)
                             end
Rendering a 500 page

•   Rails uses this to handle errors, for example in ShowExceptions middleware
     def call(env)
       @app.call(env)
     rescue Exception => exception
       raise exception if env['action_dispatch.show_exceptions'] == false
       render_exception(env, exception)
     end



•   Rails rescues the exception here, and renders a nice 500 error page
Bugsnag Logging middleware

•   Here is a simplified version of the Bugsnag error logging middleware

                           def call(env)
                             @app.call(env)
                           rescue Exception => exception
                             Bugsnag.notify(exception)
                             raise
                           end


•   But you need to make sure this goes in you middleware stack JUST before you
    render the 500 page!
SHOW The middleware stack

•   Rails has given you an awesome tool to show your middleware stack
                   $ rake middleware
                   ...
                   use ActionDispatch::ShowExceptions
                   use ActionDispatch::DebugExceptions
                   use Bugsnag::Rack
                   ...
                   use ActionDispatch::Cookies
                   use ActionDispatch::Session::CookieStore
                   use ActionDispatch::Flash
                   use ActionDispatch::ParamsParser
                   ...
                   run YourApp::Application.routes
Better Errors




•   https://github.com/charliesome/better_errors

•   Better version of DebugExceptions, used in development on Rails

•   Allows you to debug crashes when they happen
Hammertime




•   https://github.com/avdi/hammertime

•   Allows you to debug exception raises in real time in Ruby apps
PRY RESCUE




•   https://github.com/ConradIrwin/pry-rescue

•   Allows you to debug uncaught exceptions in real time in Ruby apps
Bugsnag




•   http://bugsnag.com

•   Tracks and groups your errors from development and production

•   Get notified when someone on production sees a crash!
Find out more

•   Avdi Grimm has a great book on Ruby failure handling - I highly recommend it
    (http://exceptionalruby.com/)

•   When looking into rails error handling, delving into Rails source is recommended.
Questions?
Check out www.bugsnag.com

Weitere ähnliche Inhalte

Was ist angesagt?

Samo Sedno - Copywriting. Jak sprzedawać słowem - ebook
Samo Sedno - Copywriting. Jak sprzedawać słowem - ebookSamo Sedno - Copywriting. Jak sprzedawać słowem - ebook
Samo Sedno - Copywriting. Jak sprzedawać słowem - ebookepartnerzy.com
 
Mongo dbを知ろう
Mongo dbを知ろうMongo dbを知ろう
Mongo dbを知ろうCROOZ, inc.
 
2 TomcatによるWebアプリケーションサーバ構築 第2章 Tomcat概要(2)-セッション
2 TomcatによるWebアプリケーションサーバ構築 第2章 Tomcat概要(2)-セッション2 TomcatによるWebアプリケーションサーバ構築 第2章 Tomcat概要(2)-セッション
2 TomcatによるWebアプリケーションサーバ構築 第2章 Tomcat概要(2)-セッションEnpel
 
コードレビューを文化にするまでの取り組み.pdf
コードレビューを文化にするまでの取り組み.pdfコードレビューを文化にするまでの取り組み.pdf
コードレビューを文化にするまでの取り組み.pdfssuser5ddba11
 
Webinar - Podstawy Node.js
Webinar - Podstawy Node.jsWebinar - Podstawy Node.js
Webinar - Podstawy Node.jsWojciech Kaniuka
 
Programação Orientada a Objetos com Java
Programação Orientada a Objetos com JavaProgramação Orientada a Objetos com Java
Programação Orientada a Objetos com JavaÁlvaro Farias Pinheiro
 
[125]react로개발자2명이플랫폼4개를서비스하는이야기 심상민
[125]react로개발자2명이플랫폼4개를서비스하는이야기 심상민[125]react로개발자2명이플랫폼4개를서비스하는이야기 심상민
[125]react로개발자2명이플랫폼4개를서비스하는이야기 심상민NAVER D2
 
Começando com Vue.js
Começando com Vue.jsComeçando com Vue.js
Começando com Vue.jsmarcusbalbi
 
VueとAWSAppSyncで始めるチャットアプリ開発
VueとAWSAppSyncで始めるチャットアプリ開発VueとAWSAppSyncで始めるチャットアプリ開発
VueとAWSAppSyncで始めるチャットアプリ開発Ryosuke Izumi
 
C# で Single Page Web アプリを 開発できる Blazor ― その魅力
C# で Single Page Web アプリを開発できる Blazor ― その魅力C# で Single Page Web アプリを開発できる Blazor ― その魅力
C# で Single Page Web アプリを 開発できる Blazor ― その魅力Jun-ichi Sakamoto
 
책 "제품의 탄생" 소개
책 "제품의 탄생" 소개책 "제품의 탄생" 소개
책 "제품의 탄생" 소개SANGHEE SHIN
 
PHPでWebSocketを実装してみてわかったこと
PHPでWebSocketを実装してみてわかったことPHPでWebSocketを実装してみてわかったこと
PHPでWebSocketを実装してみてわかったことksimoji
 
Introdução sobre desenvolvimento web
Introdução sobre desenvolvimento webIntrodução sobre desenvolvimento web
Introdução sobre desenvolvimento webRodrigo Rodrigues
 
Full stack web development
Full stack web developmentFull stack web development
Full stack web developmentCrampete
 

Was ist angesagt? (20)

Node.js e Express
Node.js e ExpressNode.js e Express
Node.js e Express
 
JAVA - Herança
JAVA - HerançaJAVA - Herança
JAVA - Herança
 
Samo Sedno - Copywriting. Jak sprzedawać słowem - ebook
Samo Sedno - Copywriting. Jak sprzedawać słowem - ebookSamo Sedno - Copywriting. Jak sprzedawać słowem - ebook
Samo Sedno - Copywriting. Jak sprzedawać słowem - ebook
 
Mongo dbを知ろう
Mongo dbを知ろうMongo dbを知ろう
Mongo dbを知ろう
 
2 TomcatによるWebアプリケーションサーバ構築 第2章 Tomcat概要(2)-セッション
2 TomcatによるWebアプリケーションサーバ構築 第2章 Tomcat概要(2)-セッション2 TomcatによるWebアプリケーションサーバ構築 第2章 Tomcat概要(2)-セッション
2 TomcatによるWebアプリケーションサーバ構築 第2章 Tomcat概要(2)-セッション
 
コードレビューを文化にするまでの取り組み.pdf
コードレビューを文化にするまでの取り組み.pdfコードレビューを文化にするまでの取り組み.pdf
コードレビューを文化にするまでの取り組み.pdf
 
Webinar - Podstawy Node.js
Webinar - Podstawy Node.jsWebinar - Podstawy Node.js
Webinar - Podstawy Node.js
 
Programação Orientada a Objetos com Java
Programação Orientada a Objetos com JavaProgramação Orientada a Objetos com Java
Programação Orientada a Objetos com Java
 
[125]react로개발자2명이플랫폼4개를서비스하는이야기 심상민
[125]react로개발자2명이플랫폼4개를서비스하는이야기 심상민[125]react로개발자2명이플랫폼4개를서비스하는이야기 심상민
[125]react로개발자2명이플랫폼4개를서비스하는이야기 심상민
 
Java J2EE
Java J2EEJava J2EE
Java J2EE
 
React js Demo Explanation
React js Demo ExplanationReact js Demo Explanation
React js Demo Explanation
 
Começando com Vue.js
Começando com Vue.jsComeçando com Vue.js
Começando com Vue.js
 
VueとAWSAppSyncで始めるチャットアプリ開発
VueとAWSAppSyncで始めるチャットアプリ開発VueとAWSAppSyncで始めるチャットアプリ開発
VueとAWSAppSyncで始めるチャットアプリ開発
 
POO - Aula 1
POO - Aula 1POO - Aula 1
POO - Aula 1
 
C# で Single Page Web アプリを 開発できる Blazor ― その魅力
C# で Single Page Web アプリを開発できる Blazor ― その魅力C# で Single Page Web アプリを開発できる Blazor ― その魅力
C# で Single Page Web アプリを 開発できる Blazor ― その魅力
 
책 "제품의 탄생" 소개
책 "제품의 탄생" 소개책 "제품의 탄생" 소개
책 "제품의 탄생" 소개
 
PHPでWebSocketを実装してみてわかったこと
PHPでWebSocketを実装してみてわかったことPHPでWebSocketを実装してみてわかったこと
PHPでWebSocketを実装してみてわかったこと
 
Introdução sobre desenvolvimento web
Introdução sobre desenvolvimento webIntrodução sobre desenvolvimento web
Introdução sobre desenvolvimento web
 
Angular introduction students
Angular introduction studentsAngular introduction students
Angular introduction students
 
Full stack web development
Full stack web developmentFull stack web development
Full stack web development
 

Ähnlich wie Ruby & Rails Error Handling

Exception Handling: Designing Robust Software in Ruby
Exception Handling: Designing Robust Software in RubyException Handling: Designing Robust Software in Ruby
Exception Handling: Designing Robust Software in RubyWen-Tien Chang
 
Exceptions in Ruby - Tips and Tricks
Exceptions in Ruby - Tips and TricksExceptions in Ruby - Tips and Tricks
Exceptions in Ruby - Tips and TricksDimelo R&D Team
 
Code Fast, die() Early, Throw Structured Exceptions
Code Fast, die() Early, Throw Structured ExceptionsCode Fast, die() Early, Throw Structured Exceptions
Code Fast, die() Early, Throw Structured ExceptionsJohn Anderson
 
Exception Handling: Designing Robust Software in Ruby (with presentation note)
Exception Handling: Designing Robust Software in Ruby (with presentation note)Exception Handling: Designing Robust Software in Ruby (with presentation note)
Exception Handling: Designing Robust Software in Ruby (with presentation note)Wen-Tien Chang
 
exceptions in java
exceptions in javaexceptions in java
exceptions in javajaveed_mhd
 
Exceptions in java
Exceptions in javaExceptions in java
Exceptions in javaRajkattamuri
 
Object Oriented PHP - PART-2
Object Oriented PHP - PART-2Object Oriented PHP - PART-2
Object Oriented PHP - PART-2Jalpesh Vasa
 
exception handling.pptx
exception handling.pptxexception handling.pptx
exception handling.pptxAbinayaC11
 
Exceptions in java
Exceptions in javaExceptions in java
Exceptions in javaManav Prasad
 
Code Fast, Die Young, Throw Structured Exceptions
Code Fast, Die Young, Throw Structured ExceptionsCode Fast, Die Young, Throw Structured Exceptions
Code Fast, Die Young, Throw Structured ExceptionsJohn Anderson
 
Metaprogramming in Ruby
Metaprogramming in RubyMetaprogramming in Ruby
Metaprogramming in RubyConFoo
 
Metaprogramming
MetaprogrammingMetaprogramming
Metaprogrammingjoshbuddy
 
New land of error handling in swift
New land of error handling in swiftNew land of error handling in swift
New land of error handling in swiftTsungyu Yu
 
A exception ekon16
A exception ekon16A exception ekon16
A exception ekon16Max Kleiner
 

Ähnlich wie Ruby & Rails Error Handling (20)

Exception Handling: Designing Robust Software in Ruby
Exception Handling: Designing Robust Software in RubyException Handling: Designing Robust Software in Ruby
Exception Handling: Designing Robust Software in Ruby
 
21 ruby exceptions
21 ruby exceptions21 ruby exceptions
21 ruby exceptions
 
Exceptions in Ruby - Tips and Tricks
Exceptions in Ruby - Tips and TricksExceptions in Ruby - Tips and Tricks
Exceptions in Ruby - Tips and Tricks
 
Code Fast, die() Early, Throw Structured Exceptions
Code Fast, die() Early, Throw Structured ExceptionsCode Fast, die() Early, Throw Structured Exceptions
Code Fast, die() Early, Throw Structured Exceptions
 
Exception Handling: Designing Robust Software in Ruby (with presentation note)
Exception Handling: Designing Robust Software in Ruby (with presentation note)Exception Handling: Designing Robust Software in Ruby (with presentation note)
Exception Handling: Designing Robust Software in Ruby (with presentation note)
 
Introduction to php exception and error management
Introduction to php  exception and error managementIntroduction to php  exception and error management
Introduction to php exception and error management
 
exceptions in java
exceptions in javaexceptions in java
exceptions in java
 
Exceptions in java
Exceptions in javaExceptions in java
Exceptions in java
 
8 Exception Handling
8 Exception Handling8 Exception Handling
8 Exception Handling
 
Object Oriented PHP - PART-2
Object Oriented PHP - PART-2Object Oriented PHP - PART-2
Object Oriented PHP - PART-2
 
exception handling.pptx
exception handling.pptxexception handling.pptx
exception handling.pptx
 
Ruby Gotchas
Ruby GotchasRuby Gotchas
Ruby Gotchas
 
Exceptions in java
Exceptions in javaExceptions in java
Exceptions in java
 
Code Fast, Die Young, Throw Structured Exceptions
Code Fast, Die Young, Throw Structured ExceptionsCode Fast, Die Young, Throw Structured Exceptions
Code Fast, Die Young, Throw Structured Exceptions
 
Metaprogramming in Ruby
Metaprogramming in RubyMetaprogramming in Ruby
Metaprogramming in Ruby
 
Metaprogramming
MetaprogrammingMetaprogramming
Metaprogramming
 
Ruby Gotchas
Ruby GotchasRuby Gotchas
Ruby Gotchas
 
Ruby Intro {spection}
Ruby Intro {spection}Ruby Intro {spection}
Ruby Intro {spection}
 
New land of error handling in swift
New land of error handling in swiftNew land of error handling in swift
New land of error handling in swift
 
A exception ekon16
A exception ekon16A exception ekon16
A exception ekon16
 

Kürzlich hochgeladen

DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDropbox
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyKhushali Kathiriya
 
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...apidays
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc
 
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu SubbuApidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbuapidays
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...apidays
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MIND CTI
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...DianaGray10
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...apidays
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Jeffrey Haguewood
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesrafiqahmad00786416
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherRemote DBA Services
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...apidays
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FMESafe Software
 

Kürzlich hochgeladen (20)

DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu SubbuApidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 

Ruby & Rails Error Handling

  • 1. Error Handling in Ruby & Rails Simon Maynard - Bugsnag CTO @snmaynard
  • 2. What is Bugsnag? • We help developers log and track their errors • Ruby was the first language we supported • Now support Python, PHP, Javascript, Node.js, iOS, Android & more! • Processing millions of errors every day
  • 3. What is AN ERROR? An error occurs when code is unable to complete the task asked of it. • Asked to do the impossible Account.find(nil) • A mistake in the code account = Account.new acccount.name #!?
  • 4. What is AN ERROR? • An unexpected case case account.type when "free" then # when "paid" then # else # Unexpected! end • Failure of an external element # Database down! account.save
  • 5. How to report an error? • Raise an exception • Only when the error is truly exceptional • If the error is unexpected, or a sign of bad code • Raising should be unexpected, it’s slow
  • 6. How to report an error? • Return an error value • If its to be expected or part of "normal" operation def find(id) raise InvalidIdError, "#{id} id an invalid id" unless validate_id(id) return data[id] end
  • 7. Raise Or Fail • You can use raise to raise an exception. • You can also use fail to raise an exception. def func fail "Not implemented" rescue => e raise unless e.message == "Not implemented" end
  • 8. Raise Syntax raise MyError.new("Something Broke") is the same as raise MyError, "Something Broke"
  • 9. Raise Syntax raise "Something Broke" is the same as raise RuntimeError, "Something Broke"
  • 10. Raise Syntax raise is the same as raise RuntimeError
  • 11. Raise Syntax You can also pass a backtrace when raising an exception def assert(value) raise(RuntimeError, "Something broke", caller) unless value end
  • 12. What does raise actually do? • Raise does four things, • Builds an exception object • Sets the backtrace • Sets the global error object ($!) • Starts unwinding the stack
  • 13. How does raise build the exception? You might think that raise does this def raise(klass, msg, trace) exception = klass.new(message) # ... end But actually it does this... def raise(klass, msg, trace) exception = klass.exception(message) # ... end
  • 14. How does raise build the exception? • Exception.exception • The same as Exception.new() • Exception#exception • With no arguments, it returns self • With a message, it returns a new exception with the message set
  • 15. How does raise build the exception? This means we can implement our own exception methods class Account def exception(message="Bad Account!") ValidationError.new("#{message}: #{self.errors.inspect}") end end then we can throw an instance of own object raise account unless account.save
  • 16. Global Error Object $! contains a reference to the exception currently being raised begin raise rescue puts $!.inspect end You can also require “english” to use the slightly more readable $ERROR_INFO require "english" begin raise rescue puts $ERROR_INFO.inspect end
  • 17. rescue Syntax begin rescue MyError => error end will rescue all MyError exceptions
  • 18. rescue Syntax begin rescue => error end is the same as begin rescue StandardError => error end
  • 19. Rescue Syntax begin rescue end is the same as begin rescue StandardError end
  • 20. Rescue Syntax You can also supply a list of classes to rescue begin rescue MyError, IOError => error end
  • 21. One Line Rescue Syntax value = raise rescue "fallback_value" is the same as value = begin raise rescue "fallback_value" end
  • 22. Dynamic rescues def match_message(regex) mod = Module.new (class << mod; self; end).instance_eval do define_method(:===) do |e| regex === e.message end end mod end begin raise "sample message" rescue match_message(/sample/) # Ignore end
  • 23. Re-raising exception begin raise rescue raise end is the same as begin raise rescue raise $! end
  • 24. Raising in rescue You can also change the exception message before re-raising begin raise rescue => err # Re raise with different message raise err, “Different message” end
  • 25. Raising in rescue You can raise in a rescue def func raise rescue raise "totally new exception" end You lose the context of the real error! Don’t do this!
  • 26. Raising in rescue Instead you can keep a reference to the original exception class MyError < StandardError attr_accessor :original_exception def initialize(msg, original_exception=$!) super(msg) self.original_exception = original_exception end end def func raise rescue raise MyError.new("Something broke") end
  • 27. Ensure Syntax Ensure allows you to ensure that code is run, regardless of whether an exception is raised or not. begin raise unless rand < 0.5 ensure # Always run end
  • 28. ALTERNATIVE Syntax You can also use these commands without a begin section def func(arg) raise rescue # Deal with exception ensure # Always run end
  • 29. Ensure Syntax Be careful with return inside an ensure! def func(arg) raise ensure # This return swallows the exception return 5 end
  • 30. RETRY You can also easily retry using the retry keyword def func(arg) attempts = 0 begin attempts += 1 raise rescue retry if attempts < 3 end end
  • 31. exception hierarchy Exception NoMemoryError ScriptError SignalException SystemExit StandardError fatal Interrupt LoadError ArgumentError SyntaxError IOError ... IndexError ...
  • 32. Exception hierarchy For example, while true do begin line = STDIN.gets # heavy processing rescue Exception => e puts "caught exception #{e}! ohnoes!" end end This program is almost unkillable! Don’t catch Exception!
  • 33. Exception Hierarchy You can even prevent an exit call, begin exit(1) # Or abort() rescue Exception puts "Guess again!" end # Continue... You can’t catch an exit!(1) however...
  • 34. Raise is a method • Raise is just a method on Kernel • So we can override it!
  • 35. Raise is a method We can add debugging information to each raise module RaiseDebug def raise(*args) super *args rescue Exception puts "Raising exception: #{$!.inspect}" super *args end end class Object include RaiseDebug end
  • 36. Uncaught Errors We can use a combination of $! and the ruby exit handler to log uncaught errors at_exit do if $! open('error.log', 'a') do |log_file| error = { timestamp: Time.now.utc, message: $!.message, trace: $!.backtrace, } log_file.write(error.to_json) end end end
  • 37. Throw/Catch Ruby can also throw, but its not for errors. Use throw to unwrap the stack in a non-exceptional case, saves you from using multiple break commands INFINITY = 1.0 / 0.0 catch (:done) do 1.upto(INFINITY) do |i| 1.upto(INFINITY) do |j| if some_condition throw :done end end end end
  • 38. How does rails deal with exceptions? When there is an error in your rails app, ideally we want these things to happen • 500 page rendered to show the user something went wrong • Error logged with enough information so we can fix it • Rails to continue serving requests
  • 39. How does rails deal with exceptions? • Rails uses a Rack app to process every request. • Rack apps have a middleware stack • You can easily add your own middleware so you can execute code on every request config.middleware.use(new_middleware, args) config.middleware.insert_before(existing_middleware, new_middleware, args) config.middleware.insert_after(existing_middleware, new_middleware, args) config.middleware.delete(middleware)
  • 40. RACK Middleware Request Response Middleware 1 Middleware 2 Middleware 3 Middleware 4 Rails App
  • 41. Example RACK Middleware Here is an example of a no-op middleware module OurMiddleware class Rack def initialize(app) @app = app end def call(env) @app.call(env) end end end
  • 42. Example RACK Middleware • Initialize called when rails app starts • Takes a single parameter, which is the next middleware in the stack • Perform any other initialization for your middleware def initialize(app) @app = app end
  • 43. Example RACK Middleware • Call is called for every request • @app.call calls the next middleware in the stack (or your app itself) def call(env) response = @app.call(env) end
  • 44. Rendering a 500 page • Rails uses this to handle errors, for example in ShowExceptions middleware def call(env) @app.call(env) rescue Exception => exception raise exception if env['action_dispatch.show_exceptions'] == false render_exception(env, exception) end • Rails rescues the exception here, and renders a nice 500 error page
  • 45. Bugsnag Logging middleware • Here is a simplified version of the Bugsnag error logging middleware def call(env) @app.call(env) rescue Exception => exception Bugsnag.notify(exception) raise end • But you need to make sure this goes in you middleware stack JUST before you render the 500 page!
  • 46. SHOW The middleware stack • Rails has given you an awesome tool to show your middleware stack $ rake middleware ... use ActionDispatch::ShowExceptions use ActionDispatch::DebugExceptions use Bugsnag::Rack ... use ActionDispatch::Cookies use ActionDispatch::Session::CookieStore use ActionDispatch::Flash use ActionDispatch::ParamsParser ... run YourApp::Application.routes
  • 47. Better Errors • https://github.com/charliesome/better_errors • Better version of DebugExceptions, used in development on Rails • Allows you to debug crashes when they happen
  • 48. Hammertime • https://github.com/avdi/hammertime • Allows you to debug exception raises in real time in Ruby apps
  • 49. PRY RESCUE • https://github.com/ConradIrwin/pry-rescue • Allows you to debug uncaught exceptions in real time in Ruby apps
  • 50. Bugsnag • http://bugsnag.com • Tracks and groups your errors from development and production • Get notified when someone on production sees a crash!
  • 51. Find out more • Avdi Grimm has a great book on Ruby failure handling - I highly recommend it (http://exceptionalruby.com/) • When looking into rails error handling, delving into Rails source is recommended.

Hinweis der Redaktion

  1. experience of monitoring apps at scale heyzap
  2. example errors
  3. Performance
  4. Return an error value if its common or people will use to test Validation function shouldnt raise if invalid e.g mongoid find raising by default, at least you can change if you want
  5. raise = fail raise common some use fail to be when failing for first time, raise in rescue blocks
  6. exception is like to_s, but for exceptions
  7. Can attach exception methods to objects easily, so they can be raised
  8. These are just examples, empty rescue blocks are a code smell, at least have a log in there!
  9. Bad as it catches all StandardErrors, you should catch explicit exception types, more on that later
  10. Rescue calls === on the error and the object passed to rescue, so we can override
  11. This is a common pattern in ruby, getting more popular - rails does it when you have an error in your view for example converts to template error
  12. Exception hierarchy shows why you should never catch exception
  13. Be specific when you catch something
  14. Note here I rescue exception, but I always re-raise :-)
  15. Sinatra uses this when using etags i believe, to prevent recalculating a still valid response
  16. Middleware performance is important Crashes in middleware are very bad