# module Timeout

Timeout long-running blocks

## Synopsis¶ ↑

    require 'timeout'
    status = Timeout::timeout(5) {
      # Something that should be interrupted if it takes more than 5 seconds...
    }

## Description¶ ↑

Timeout provides a way to auto-terminate a potentially long-running operation if it hasn't finished in a fixed amount of time.

Previous versions didn't use a module for namespacing, however timeout is provided for backwards compatibility. You should prefer #timeout instead.

## Copyright¶ ↑

Copyright

  (C) 2000 Network Applied Communication Laboratory, Inc.

Copyright

  (C) 2000 Information-technology Promotion Agency, Japan

### Public Class Methods

timeout(sec, klass = nil, message = nil) { |sec| ... } click to toggle source

Perform an operation in a block, raising an error if it takes longer than `sec` seconds to complete.

`sec`

  Number of seconds to wait for the block to terminate. Any number may be used, including Floats to specify fractional seconds. A value of 0 or `nil` will execute the block without any timeout.

`klass`

  Exception Class to raise if the block fails to terminate in `sec` seconds. Omitting will use the default, Timeout::Error

`message`

  Error message to raise with Exception Class. Omitting will use the default, “execution expired”

Returns the result of the block if the block completed before `sec` seconds, otherwise throws an exception, based on the value of `klass`.

The exception thrown to terminate the given block cannot be rescued inside the block unless `klass` is given explicitly.

Note that this is both a method of module Timeout, so you can `include Timeout` into your classes so they have a timeout method, as well as a module method, so you can call it directly as #timeout.

    # File lib/timeout.rb, line 74
    def timeout(sec, klass = nil, message = nil)   #:yield: +sec+
      return yield(sec) if sec == nil or sec.zero?
      message ||= "execution expired".freeze
      from = "from #{caller_locations(1, 1)[0]}" if $DEBUG
      e = Error
      bl = proc do |exception|
        begin
          x = Thread.current
          y = Thread.start {
            Thread.current.name = from
            begin
              sleep sec
            rescue => e
              x.raise e
            else
              x.raise exception, message
            end
          }
          return yield(sec)
        ensure
          if y
            y.kill
            y.join # make sure y is dead.
          end
        end
      end
      if klass
        begin
          bl.call(klass)
        rescue klass => e
          bt = e.backtrace
        end
      else
        bt = Error.catch(message, &bl)
      end
      level = -caller(CALLER_OFFSET).size-2
      while THIS_FILE =~ bt[level]
        bt.delete_at(level)
      end
      raise(e, message, bt)
    end

### Private Instance Methods

timeout(sec, klass = nil, message = nil) { |sec| ... } click to toggle source

Perform an operation in a block, raising an error if it takes longer than `sec` seconds to complete.

`sec`

  Number of seconds to wait for the block to terminate. Any number may be used, including Floats to specify fractional seconds. A value of 0 or `nil` will execute the block without any timeout.

`klass`

  Exception Class to raise if the block fails to terminate in `sec` seconds. Omitting will use the default, Timeout::Error

`message`

  Error message to raise with Exception Class. Omitting will use the default, “execution expired”

Returns the result of the block if the block completed before `sec` seconds, otherwise throws an exception, based on the value of `klass`.

The exception thrown to terminate the given block cannot be rescued inside the block unless `klass` is given explicitly.

Note that this is both a method of module Timeout, so you can `include Timeout` into your classes so they have a timeout method, as well as a module method, so you can call it directly as #timeout.

    # File lib/timeout.rb, line 74
    def timeout(sec, klass = nil, message = nil)   #:yield: +sec+
      return yield(sec) if sec == nil or sec.zero?
      message ||= "execution expired".freeze
      from = "from #{caller_locations(1, 1)[0]}" if $DEBUG
      e = Error
      bl = proc do |exception|
        begin
          x = Thread.current
          y = Thread.start {
            Thread.current.name = from
            begin
              sleep sec
            rescue => e
              x.raise e
            else
              x.raise exception, message
            end
          }
          return yield(sec)
        ensure
          if y
            y.kill
            y.join # make sure y is dead.
          end
        end
      end
      if klass
        begin
          bl.call(klass)
        rescue klass => e
          bt = e.backtrace
        end
      else
        bt = Error.catch(message, &bl)
      end
      level = -caller(CALLER_OFFSET).size-2
      while THIS_FILE =~ bt[level]
        bt.delete_at(level)
      end
      raise(e, message, bt)
    end