Pergunta

I'm trying to create a class method that will put a timeout wrapper around other class methods.

class FooBar

  def self.slow_add(a,b,c)
    sleep 1
    a + b + c
  end

  LIST = [:slow_add]

  class << self
    LIST.each do |x|
      alias_method "#{x}_without_timeout", "#{x}"
      define_method("#{x}_with_timeout") do |*args|
        timeout(4){self.send(x, *args)}
      end
      alias_method "#{x}", "#{x}_with_timeout"
    end
  end
end

However, the resulting timeout methods always times out, even though they shouldn't:

2.0.0p353 :152 >   FooBar.slow_add_without_timeout(1, 2, 3)
 => 6 
2.0.0p353 :153 > FooBar.slow_add_with_timeout(1, 2, 3)
Timeout::Error: execution expired
...
...
2.0.0p353 :156 >   FooBar.slow_add(1, 2, 3)
Timeout::Error: execution expired
...
...

Thanks for your help.

Foi útil?

Solução

If it's important that you're able to send a timeout message to your class, I would recommend creating an auxillary class that would wrap every method call in a timeout block and forward the message onto the original reference object. Something like this:

require 'timeout'

class TimeoutHandler
  attr_reader :seconds, :object
  def initialize(object, seconds)
    @seconds = seconds
    @object = object
  end

  def method_missing(name, *args, &block)
    Timeout::timeout(seconds){ object.send(name, *args, &block) }
  end
end

You would create instance of the TimeoutHandler like this:

class FooBar
  class << self
    def timeout(seconds = 4)
      TimeoutHandler.new(self, seconds)
    end
  end
end

So then anytime you need to interrupt a message with a timeout block, you simply call timeout on it first:

FooBar.timeout.slow_add(1, 2, 3)

You could write the timeout method in a mixin to be included in classes where you need this functionality.

However, all of this seems very contrived to me, and I would need a pretty good reason to implement it rather than just using the much simpler Timeout::timeout { FooBar.slow_add(1, 2, 3) }, which doesn't require any additional implementation.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top