Rescue Timeout :: Ошибка от Redis Gem (Ruby) - PullRequest
1 голос
/ 12 августа 2011

Мне нужно спасти Timeout::Error, поднятый из библиотеки Redis, но я столкнулся с проблемой, спасение этого конкретного класса, похоже, не работает.

begin
  Redis.new( { :host => "127.0.0.X" } )
rescue Timeout::Error => ex
end

=> Timeout::Error: Timeout::Error from /Users/me/.rvm/gems/ree-1.8.7-2011.03@gowalla/gems/redis-2.2.0/lib/redis/connection/hiredis.rb:23:in `connect'

Когда я пытаюсь спасти Exception, он все равно не работает

begin
  Redis.new( { :host => "127.0.0.X" } )
rescue Exception => ex
end

=> Timeout::Error: Timeout::Error from /Users/me/.rvm/gems/ree-1.8.7-2011.03@gowalla/gems/redis-2.2.0/lib/redis/connection/hiredis.rb:23:in `connect'

Если я пытаюсь вызвать исключение вручную, я могу его спасти, но не знаюпочему я не могу спасти его, когда он вызывается из Redis Gem (2.2.0).

begin
  raise Timeout::Error
rescue Timeout::Error => ex
  puts ex 
end

Timeout::Error
=> nil 

Есть подсказка, как спасти это исключение?

1 Ответ

5 голосов
/ 12 августа 2011

Вы запустили этот код в irb, верно?Исключение, которое вы получаете, на самом деле не увеличивается на Redis.new.Он вызывается методом inspect, который irb вызывает, чтобы показать вам значение только что введенного выражения.

Просто посмотрите на трассировку стека (я сократил пути, чтобы сделать его разборчивым):

ruby-1.8.7-p330 :009 >   Redis.new(:host => "google.com")
Timeout::Error: time's up!
    from /.../SystemTimer-1.2.3/lib/system_timer/concurrent_timer_pool.rb:63:in `trigger_next_expired_timer_at'
    from /.../SystemTimer-1.2.3/lib/system_timer/concurrent_timer_pool.rb:68:in `trigger_next_expired_timer'
    from /.../SystemTimer-1.2.3/lib/system_timer.rb:85:in `install_ruby_sigalrm_handler'
    from /..../lib/ruby/1.8/monitor.rb:242:in `synchronize'
    from /.../SystemTimer-1.2.3/lib/system_timer.rb:83:in `install_ruby_sigalrm_handler'
    from /.../redis-2.2.2/lib/redis/connection/ruby.rb:26:in `call'
    from /.../redis-2.2.2/lib/redis/connection/ruby.rb:26:in `initialize'
    from /.../redis-2.2.2/lib/redis/connection/ruby.rb:26:in `new'
    from /.../redis-2.2.2/lib/redis/connection/ruby.rb:26:in `connect'
    from /.../SystemTimer-1.2.3/lib/system_timer.rb:60:in `timeout_after'
    from /.../redis-2.2.2/lib/redis/connection/ruby.rb:115:in `with_timeout'
    from /.../redis-2.2.2/lib/redis/connection/ruby.rb:25:in `connect'
    from /.../redis-2.2.2/lib/redis/client.rb:227:in `establish_connection'
    from /.../redis-2.2.2/lib/redis/client.rb:23:in `connect'
    from /.../redis-2.2.2/lib/redis/client.rb:247:in `ensure_connected'
    from /.../redis-2.2.2/lib/redis/client.rb:137:in `process'
... 2 levels...
    from /.../redis-2.2.2/lib/redis/client.rb:46:in `call'
    from /.../redis-2.2.2/lib/redis.rb:90:in `info'
    from /..../lib/ruby/1.8/monitor.rb:242:in `synchronize'
    from /.../redis-2.2.2/lib/redis.rb:89:in `info'
    from /.../redis-2.2.2/lib/redis.rb:1075:in `inspect'
    from /..../lib/ruby/1.8/monitor.rb:242:in `synchronize'
    from /.../redis-2.2.2/lib/redis.rb:1074:in `inspect'
    from /..../lib/ruby/1.8/irb.rb:310:in `output_value'
    from /..../lib/ruby/1.8/irb.rb:159:in `eval_input'
    from /..../lib/ruby/1.8/irb.rb:271:in `signal_status'
    from /..../lib/ruby/1.8/irb.rb:155:in `eval_input'
    from /..../lib/ruby/1.8/irb.rb:154:in `eval_input'
    from /..../lib/ruby/1.8/irb.rb:71:in `start'
    from /..../lib/ruby/1.8/irb.rb:70:in `catch'
    from /..../lib/ruby/1.8/irb.rb:70:in `start'
    from /..../bin/irb:17

Как вы можете видеть выше, исключение происходит внутри inspect, а не Redis.new.Когда вы вызываете inspect для объекта Redis, вместо того, чтобы просто распечатывать его состояние, он на самом деле делает много вещей.В этом случае inspect пытается подключиться к серверу и выдает исключение по истечении этого времени.Мне кажется, что это очень плохой дизайн, и, возможно, нам следует подать отчет об ошибке сопровождающим Gem Redis.

Это приводит к интересному поведению в IRB:

  • ПечатаниеRedis.new(:host => "google.com") приводит к исключению, как показано выше
  • Ввод Redis.new(:host => "google.com"); 'hello' приводит к '=> "hello"'

Если вы хотите перехватить это исключение, попробуйте вызвать ensure_connectedваш начальный / спасательный / конечный блок.

...