SlideShare une entreprise Scribd logo
1  sur  26
Exceptions in Ruby
                         Tips & Tricks

                                       Vlad ZLOTEANU
     #ParisRB
     July 3, 2002             Software Engineer @ Dimelo
                                           @vladzloteanu

Copyright Dimelo SA                             www.dimelo.com
About me


           R&D Software Engineer @ Dimelo

           @vladzloteanu

           https://github.com/vladzloteanu




Copyright Dimelo SA                          www.dimelo.com
Exceptions (in Ruby)



         Failure: abnormal situation

      Exception: instance of Exception class (or instance of
     descendant)
          What: allows packaging info about the failure
             message string
             backtrace
          default behavior: program terminates (exits)


Copyright Dimelo SA                                  www.dimelo.com
Exceptions classes in Ruby

                      Exception
                         NoMemoryError
                         ScriptError
                            LoadError
                         SignalException
                            Interrupt
                         StandardError
                            ArgumentError
                            IOError ...
                            RuntimeError
                         SystemExit
Copyright Dimelo SA                           www.dimelo.com
Raising an exception

    class MyException < StandardError; end


    raise MyException.new


    raise # aka: raise RuntimeError.new


    raise “Boom!!” # aka raise RuntimeError.new(“Boom!!”)


    raise MyException, “Boom!!”, backtrace




Copyright Dimelo SA                              www.dimelo.com
Rescuing exceptions

    begin
      raise MyError.new("Booooom!")

    rescue MyError
      puts "MyError just hapened"

    rescue # Will rescue StandardError
      puts "a RuntimeError just happened"

    rescue Exception => e
      puts ”Exception: #{e.message}”
      e.backtrace.each{|line| puts “ > #{line}”}

    end




Copyright Dimelo SA                                www.dimelo.com
Intermezzo: Signals

                      Signals – used to alert threads/processes
                      (hardware faults, timer expiration, terminal
                      activity, kill command, etc)
                         SIGINT: CTRL+C in terminal (can be caught)
                         SIGTERM: Sent by kill command by default
                         (can be caught)
                         SIGKILL: Uncatchable exception (kill -9)

                      A SignalException is raised when a signal is
                      received


Copyright Dimelo SA                                          www.dimelo.com
What should we rescue?




Copyright Dimelo SA                       www.dimelo.com
Rescuing exceptions


                      TIP: DON’T RESCUE ‘EXCEPTION’ class!

    begin


      while(true) ; end
    rescue Exception
      puts "Rescued exception; Will retry"
      retry
    end

    ^CRescued exception; WIll retry
    ^CRescued exception; WIll retry
    ^CRescued exception; WIll retry

    # Kill -9, baby!
Copyright Dimelo SA                                          www.dimelo.com
Rescuing exceptions (third-party libraries)

    # You may think this will save you from all evil ..
    begin
      Net::HTTP.get_response(’external.resource', '/')
    rescue => e
      […]


    # Think again!

    # Excerpt from net/http.rb
    def connect
        s = timeout(@open_timeout)
             { TCPSocket.open(conn_address(), conn_port()) }

         Net::HTTP(Timeout library) may throw
         Timeout::Error < InterruptError
Copyright Dimelo SA                                     www.dimelo.com
Rescuing exceptions (third-party libraries)

    # Solution is easy:

    begin
      Net::HTTP.get_response(’external.resource', '/')
    rescue StandardError, Timeout::Error => e
      […]




         Tip: Net::HTTP (and many of the gems that
         depend on it) can throw Timeout::Error – don’t
         forget to rescue it


Copyright Dimelo SA                                     www.dimelo.com
Rescuing exceptions - cont


                      TIP: (rescue blocks): rescue most specific
                      errors first, most generic last

                      TIP: inline rescue
                         but avoid it because:
                                 No access to rescued exception
                                 Exceptions are slow (explained later)
    # Will return: DefaultDecorator
    @decorator = “foo”.constantize rescue DefaultDecorator




Copyright Dimelo SA                                           www.dimelo.com
What should we raise?




Copyright Dimelo SA                      www.dimelo.com
Raising exceptions


                      Tip: make your own exception class, do not
                      “raise string”
                         avoid using error message for making
                         discriminating error type
   begin
     if @avatar_url.empty?
       raise “Input should not be empty”
     elsif @avatar_url.valid?
       raise “Avatar URL invalid”
     end

   rescue RuntimeError => e
     # They are both instances of RuntimeError, can’t
     # rescue only the first one
   end
Copyright Dimelo SA                                        www.dimelo.com
Raising exceptions (cont)

    # excerpt from OpenSSL::SSLError
    # - invalid certificate, invalid hostname, protocol
    mismatch, etc.
    class SSLError
      def initialize(message)
        @message = message
      end
    […]

    # Client code
    rescue OpenSSL::SSL::SSLError => e
      if e.message =~ /sslv3 alert unexpected message/
        @conn.ssl_version="SSLv3“
        retry
      else
        raise


Copyright Dimelo SA                              www.dimelo.com
Getting latest exception



    begin
      raise ”Boom!"
    rescue
      puts $!.inspect
        # > #<RuntimeError: Boom!>
    end

    puts $!.inspect
      # > nil

    1 / 0 rescue nil
    puts $!.inspect
      # > nil


Copyright Dimelo SA                         www.dimelo.com
Intermezzo: caller method


                      TIP: ’caller’ gets you current execution
                      stacktrace

    def foo
        bar
    end

    def bar
        puts caller.inspect
    end

    foo
      # [”test_caller:2:in `foo'",
         ”test_caller.rb:9"]

Copyright Dimelo SA                                          www.dimelo.com
Re-raise exception – backtrace issue

    def foo
      Net::HTTP.get_response('does.not.exists', '/')
    rescue => e
      # some logging, or whatever..

      # raising a new error
      raise MyCustomException.new(‘Boom!’)
    end

    begin
      foo
    rescue => e
      puts e.backtrace.inspect
    end

    ["reraise_ex.rb:7:in `foo'", "reraise_ex.rb:11"]


Copyright Dimelo SA                                     www.dimelo.com
Re-raise exception – backtrace issue (2)


                      TIP: when reraising new exception, ensure you
                      don’t loose the backtrace

    def foo
       Net::HTTP.get_response('does.not.exists', '/')
    rescue => e

        # raising a new error, keeping old backtrace
        raise MyException, "And now.. boom!", e.backtrace

      # another option is to reraise same error:
      raise
    End



Copyright Dimelo SA                                        www.dimelo.com
Ensure
 begin
   puts '> always executed (even if there was
            normal flow’                        or there
   raise "error in normal flow”
   puts "< was not flow"
            normal an exception)
 rescue
           good place for code cleanup
   puts "> RESCUE - last error is <#{$!}>”
   raise "error in rescue”
   puts "< RESCUE"
 ensure
   puts "> ENSURE - last error is <#{$!}>”
   raise "error in ensure”
   puts "< ENSURE after raising"
 end

   ruby raise_rescue.rb
   > normal flow
   > RESCUE - last error is <error in normal flow>
   > ENSURE - last error is <error in rescue>
                                                 www.dimelo.com
   raise_rescue.rb:11: error in ensure (RuntimeError)
Copyright Dimelo SA
Catch/throw


            ruby ‘goto label’ implementation
            should be used on ‘expected’ situations

  # Sinatra code

  def last_modified(time)
    response['Last-Modified'] = time
    request.env['HTTP_IF_MODIFIED_SINCE'] > time
      throw :halt, response
    end
  end

    def invoke
         res = catch(:halt) { yield }
         ..
    end
Copyright Dimelo SA                               www.dimelo.com
Exceptions are slow ?

         https://github.com/vladzloteanu/ruby_exceptions_benchmark


  user_name = ““
                                                          ~ 0.3ns
  # Test with ‘if’
  nil if user_name.empty?

  # Test with raise/rescue
  begin                                                   ~ 74 ns
    raise "boom!" if user_name.empty?
  rescue => e
    nil
  end
                                                          ~ 2 ns
    # Test with try/catch
    catch(:error) do
       throw :error if user_name.empty?
    end
Copyright Dimelo SA                                                 www.dimelo.com
Exceptions are slow ? (2)


    class User < ActiveRecord::Base
      validates :email, :presence => true
    end

    user = User.new

    # Test with ‘if’
                                             ~ 1.5 ms
    nil unless user.save

    # Test with raise/rescue
                                             ~ 2 ms
    user.save! rescue nil




Copyright Dimelo SA                                   www.dimelo.com
Exceptions are slow ? (3)


                      TIP: Exceptions should be used only on
                      ‘exceptional’ situations
                         Use conditional constructs or ‘throw’ for
                         expected cases
                      TIP: Detect errors at low level, handle them at
                      high level




Copyright Dimelo SA                                          www.dimelo.com
Recap


                      Don’t rescue Exception!
                      Watch out for exceptions thrown by your libs
                      (Timeout::Error on Net::HTTP) Avoid putting
                      error type (only) in exception message
                      Avoid using exceptions for normal program
                      flow
                          Exceptions are slow(er)
                      Catch errors on the caller code, not on the
                      callee
                      When you reraise, ensure that you don’t
                      loose initial error’s backtrace
Copyright Dimelo SA                                        www.dimelo.com
Thank you!


                      Questions?




                      http://jobs.dimelo.com ;)



Copyright Dimelo SA                               www.dimelo.com

Contenu connexe

Similaire à Exceptions in Ruby - Tips and Tricks

Enhance you APDEX.. naturally!
Enhance you APDEX.. naturally!Enhance you APDEX.. naturally!
Enhance you APDEX.. naturally!Dimelo R&D Team
 
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
 
Perl exceptions lightning talk
Perl exceptions lightning talkPerl exceptions lightning talk
Perl exceptions lightning talkPeter Edwards
 
Python Programming Essentials - M21 - Exception Handling
Python Programming Essentials - M21 - Exception HandlingPython Programming Essentials - M21 - Exception Handling
Python Programming Essentials - M21 - Exception HandlingP3 InfoTech Solutions Pvt. Ltd.
 
A exception ekon16
A exception ekon16A exception ekon16
A exception ekon16Max Kleiner
 
Exception handling in c
Exception handling in cException handling in c
Exception handling in cMemo Yekem
 
Exception handling in c
Exception handling in cException handling in c
Exception handling in cMemo Yekem
 
Troubleshooting Plone
Troubleshooting PloneTroubleshooting Plone
Troubleshooting PloneRicado Alves
 
Error and exception in python
Error and exception in pythonError and exception in python
Error and exception in pythonjunnubabu
 
Getting modern with logging via log4perl
Getting modern with logging via log4perlGetting modern with logging via log4perl
Getting modern with logging via log4perlDean Hamstead
 
Exceptions in java
Exceptions in javaExceptions in java
Exceptions in javaManav Prasad
 
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
 
Course 102: Lecture 8: Composite Commands
Course 102: Lecture 8: Composite Commands Course 102: Lecture 8: Composite Commands
Course 102: Lecture 8: Composite Commands Ahmed El-Arabawy
 
Monkeybars in the Manor
Monkeybars in the ManorMonkeybars in the Manor
Monkeybars in the Manormartinbtt
 
Questioning the status quo
Questioning the status quoQuestioning the status quo
Questioning the status quoIvano Pagano
 
Decompiling Java - SCAM2009 Presentation
Decompiling Java - SCAM2009 PresentationDecompiling Java - SCAM2009 Presentation
Decompiling Java - SCAM2009 PresentationJames Hamilton
 
Aprendendo solid com exemplos
Aprendendo solid com exemplosAprendendo solid com exemplos
Aprendendo solid com exemplosvinibaggio
 

Similaire à Exceptions in Ruby - Tips and Tricks (20)

Enhance you APDEX.. naturally!
Enhance you APDEX.. naturally!Enhance you APDEX.. naturally!
Enhance you APDEX.. naturally!
 
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
 
Perl exceptions lightning talk
Perl exceptions lightning talkPerl exceptions lightning talk
Perl exceptions lightning talk
 
Python Programming Essentials - M21 - Exception Handling
Python Programming Essentials - M21 - Exception HandlingPython Programming Essentials - M21 - Exception Handling
Python Programming Essentials - M21 - Exception Handling
 
A exception ekon16
A exception ekon16A exception ekon16
A exception ekon16
 
Exception handling in c
Exception handling in cException handling in c
Exception handling in c
 
Exception handling in c
Exception handling in cException handling in c
Exception handling in c
 
Vagrant for real
Vagrant for realVagrant for real
Vagrant for real
 
Troubleshooting Plone
Troubleshooting PloneTroubleshooting Plone
Troubleshooting Plone
 
Error and exception in python
Error and exception in pythonError and exception in python
Error and exception in python
 
Getting modern with logging via log4perl
Getting modern with logging via log4perlGetting modern with logging via log4perl
Getting modern with logging via log4perl
 
From dot net_to_rails
From dot net_to_railsFrom dot net_to_rails
From dot net_to_rails
 
Exceptions in java
Exceptions in javaExceptions in java
Exceptions in java
 
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)
 
Course 102: Lecture 8: Composite Commands
Course 102: Lecture 8: Composite Commands Course 102: Lecture 8: Composite Commands
Course 102: Lecture 8: Composite Commands
 
Monkeybars in the Manor
Monkeybars in the ManorMonkeybars in the Manor
Monkeybars in the Manor
 
Namespaces
NamespacesNamespaces
Namespaces
 
Questioning the status quo
Questioning the status quoQuestioning the status quo
Questioning the status quo
 
Decompiling Java - SCAM2009 Presentation
Decompiling Java - SCAM2009 PresentationDecompiling Java - SCAM2009 Presentation
Decompiling Java - SCAM2009 Presentation
 
Aprendendo solid com exemplos
Aprendendo solid com exemplosAprendendo solid com exemplos
Aprendendo solid com exemplos
 

Dernier

A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?Igalia
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
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
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
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
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?Antenna Manufacturer Coco
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsJoaquim Jorge
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CVKhem
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
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
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 

Dernier (20)

A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
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
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
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
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
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...
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 

Exceptions in Ruby - Tips and Tricks

  • 1. Exceptions in Ruby Tips & Tricks Vlad ZLOTEANU #ParisRB July 3, 2002 Software Engineer @ Dimelo @vladzloteanu Copyright Dimelo SA www.dimelo.com
  • 2. About me R&D Software Engineer @ Dimelo @vladzloteanu https://github.com/vladzloteanu Copyright Dimelo SA www.dimelo.com
  • 3. Exceptions (in Ruby) Failure: abnormal situation Exception: instance of Exception class (or instance of descendant) What: allows packaging info about the failure message string backtrace default behavior: program terminates (exits) Copyright Dimelo SA www.dimelo.com
  • 4. Exceptions classes in Ruby Exception NoMemoryError ScriptError LoadError SignalException Interrupt StandardError ArgumentError IOError ... RuntimeError SystemExit Copyright Dimelo SA www.dimelo.com
  • 5. Raising an exception class MyException < StandardError; end raise MyException.new raise # aka: raise RuntimeError.new raise “Boom!!” # aka raise RuntimeError.new(“Boom!!”) raise MyException, “Boom!!”, backtrace Copyright Dimelo SA www.dimelo.com
  • 6. Rescuing exceptions begin raise MyError.new("Booooom!") rescue MyError puts "MyError just hapened" rescue # Will rescue StandardError puts "a RuntimeError just happened" rescue Exception => e puts ”Exception: #{e.message}” e.backtrace.each{|line| puts “ > #{line}”} end Copyright Dimelo SA www.dimelo.com
  • 7. Intermezzo: Signals Signals – used to alert threads/processes (hardware faults, timer expiration, terminal activity, kill command, etc) SIGINT: CTRL+C in terminal (can be caught) SIGTERM: Sent by kill command by default (can be caught) SIGKILL: Uncatchable exception (kill -9) A SignalException is raised when a signal is received Copyright Dimelo SA www.dimelo.com
  • 8. What should we rescue? Copyright Dimelo SA www.dimelo.com
  • 9. Rescuing exceptions TIP: DON’T RESCUE ‘EXCEPTION’ class! begin while(true) ; end rescue Exception puts "Rescued exception; Will retry" retry end ^CRescued exception; WIll retry ^CRescued exception; WIll retry ^CRescued exception; WIll retry # Kill -9, baby! Copyright Dimelo SA www.dimelo.com
  • 10. Rescuing exceptions (third-party libraries) # You may think this will save you from all evil .. begin Net::HTTP.get_response(’external.resource', '/') rescue => e […] # Think again! # Excerpt from net/http.rb def connect s = timeout(@open_timeout) { TCPSocket.open(conn_address(), conn_port()) } Net::HTTP(Timeout library) may throw Timeout::Error < InterruptError Copyright Dimelo SA www.dimelo.com
  • 11. Rescuing exceptions (third-party libraries) # Solution is easy: begin Net::HTTP.get_response(’external.resource', '/') rescue StandardError, Timeout::Error => e […] Tip: Net::HTTP (and many of the gems that depend on it) can throw Timeout::Error – don’t forget to rescue it Copyright Dimelo SA www.dimelo.com
  • 12. Rescuing exceptions - cont TIP: (rescue blocks): rescue most specific errors first, most generic last TIP: inline rescue but avoid it because: No access to rescued exception Exceptions are slow (explained later) # Will return: DefaultDecorator @decorator = “foo”.constantize rescue DefaultDecorator Copyright Dimelo SA www.dimelo.com
  • 13. What should we raise? Copyright Dimelo SA www.dimelo.com
  • 14. Raising exceptions Tip: make your own exception class, do not “raise string” avoid using error message for making discriminating error type begin if @avatar_url.empty? raise “Input should not be empty” elsif @avatar_url.valid? raise “Avatar URL invalid” end rescue RuntimeError => e # They are both instances of RuntimeError, can’t # rescue only the first one end Copyright Dimelo SA www.dimelo.com
  • 15. Raising exceptions (cont) # excerpt from OpenSSL::SSLError # - invalid certificate, invalid hostname, protocol mismatch, etc. class SSLError def initialize(message) @message = message end […] # Client code rescue OpenSSL::SSL::SSLError => e if e.message =~ /sslv3 alert unexpected message/ @conn.ssl_version="SSLv3“ retry else raise Copyright Dimelo SA www.dimelo.com
  • 16. Getting latest exception begin raise ”Boom!" rescue puts $!.inspect # > #<RuntimeError: Boom!> end puts $!.inspect # > nil 1 / 0 rescue nil puts $!.inspect # > nil Copyright Dimelo SA www.dimelo.com
  • 17. Intermezzo: caller method TIP: ’caller’ gets you current execution stacktrace def foo bar end def bar puts caller.inspect end foo # [”test_caller:2:in `foo'", ”test_caller.rb:9"] Copyright Dimelo SA www.dimelo.com
  • 18. Re-raise exception – backtrace issue def foo Net::HTTP.get_response('does.not.exists', '/') rescue => e # some logging, or whatever.. # raising a new error raise MyCustomException.new(‘Boom!’) end begin foo rescue => e puts e.backtrace.inspect end ["reraise_ex.rb:7:in `foo'", "reraise_ex.rb:11"] Copyright Dimelo SA www.dimelo.com
  • 19. Re-raise exception – backtrace issue (2) TIP: when reraising new exception, ensure you don’t loose the backtrace def foo Net::HTTP.get_response('does.not.exists', '/') rescue => e # raising a new error, keeping old backtrace raise MyException, "And now.. boom!", e.backtrace # another option is to reraise same error: raise End Copyright Dimelo SA www.dimelo.com
  • 20. Ensure begin puts '> always executed (even if there was normal flow’ or there raise "error in normal flow” puts "< was not flow" normal an exception) rescue good place for code cleanup puts "> RESCUE - last error is <#{$!}>” raise "error in rescue” puts "< RESCUE" ensure puts "> ENSURE - last error is <#{$!}>” raise "error in ensure” puts "< ENSURE after raising" end ruby raise_rescue.rb > normal flow > RESCUE - last error is <error in normal flow> > ENSURE - last error is <error in rescue> www.dimelo.com raise_rescue.rb:11: error in ensure (RuntimeError) Copyright Dimelo SA
  • 21. Catch/throw ruby ‘goto label’ implementation should be used on ‘expected’ situations # Sinatra code def last_modified(time) response['Last-Modified'] = time request.env['HTTP_IF_MODIFIED_SINCE'] > time throw :halt, response end end def invoke res = catch(:halt) { yield } .. end Copyright Dimelo SA www.dimelo.com
  • 22. Exceptions are slow ? https://github.com/vladzloteanu/ruby_exceptions_benchmark user_name = ““ ~ 0.3ns # Test with ‘if’ nil if user_name.empty? # Test with raise/rescue begin ~ 74 ns raise "boom!" if user_name.empty? rescue => e nil end ~ 2 ns # Test with try/catch catch(:error) do throw :error if user_name.empty? end Copyright Dimelo SA www.dimelo.com
  • 23. Exceptions are slow ? (2) class User < ActiveRecord::Base validates :email, :presence => true end user = User.new # Test with ‘if’ ~ 1.5 ms nil unless user.save # Test with raise/rescue ~ 2 ms user.save! rescue nil Copyright Dimelo SA www.dimelo.com
  • 24. Exceptions are slow ? (3) TIP: Exceptions should be used only on ‘exceptional’ situations Use conditional constructs or ‘throw’ for expected cases TIP: Detect errors at low level, handle them at high level Copyright Dimelo SA www.dimelo.com
  • 25. Recap Don’t rescue Exception! Watch out for exceptions thrown by your libs (Timeout::Error on Net::HTTP) Avoid putting error type (only) in exception message Avoid using exceptions for normal program flow Exceptions are slow(er) Catch errors on the caller code, not on the callee When you reraise, ensure that you don’t loose initial error’s backtrace Copyright Dimelo SA www.dimelo.com
  • 26. Thank you! Questions? http://jobs.dimelo.com ;) Copyright Dimelo SA www.dimelo.com