Timeouts in Ruby

Timeouts are important for programs that connect to external resources or that otherwise need to bound execution time. Implementing timeouts in Ruby is straightforward using threads and the Timeout module.

require 'timeout'

def main
  # For our example, suppose we're executing an external
  # call that returns its result after 2 seconds. We'll use
  # a thread to simulate this behavior.
  t1 = Thread.new do
    sleep 2
    "result 1"
  end

  # Here's the implementation of a timeout.
  # We use the Timeout module to set a timeout of 1 second.
  # If the operation takes more than the allowed 1s, it will raise
  # a Timeout::Error exception.
  begin
    Timeout.timeout(1) do
      result = t1.value
      puts result
    end
  rescue Timeout::Error
    puts "timeout 1"
  end

  # If we allow a longer timeout of 3s, then the operation
  # will succeed and we'll print the result.
  t2 = Thread.new do
    sleep 2
    "result 2"
  end

  begin
    Timeout.timeout(3) do
      result = t2.value
      puts result
    end
  rescue Timeout::Error
    puts "timeout 2"
  end
end

main

Running this program shows the first operation timing out and the second succeeding.

$ ruby timeouts.rb
timeout 1
result 2

In this Ruby implementation:

  1. We use the Thread class to simulate asynchronous operations.
  2. The Timeout module is used to implement timeouts.
  3. We use begin/rescue blocks to handle timeout exceptions.
  4. The Thread#value method is used to get the result of a thread, which will block until the thread finishes.

This approach provides similar functionality to the original example, allowing us to set timeouts for operations and handle cases where operations exceed their allotted time.