Rescue Timeout :: Error de Redis Gem (Ruby)

Necesito rescatar un Timeout::Error generado desde la biblioteca de Redis pero me estoy encontrando con un problema, rescatar esa clase específica no parece funcionar.

 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' 

Cuando bash rescatar a Exception todavía no funciona

 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' 

Si trato de boost la excepción manualmente, puedo rescatarla pero no sé por qué no puedo rescatarla cuando se llama desde Redis Gem (2.2.0).

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

¿Alguna pista de cómo rescatar esta excepción?

Usted corrió este código en irb, ¿verdad? La excepción que está obteniendo no está siendo Redis.new por Redis.new . Se está generando mediante el método de inspect , que irb llama para mostrarle el valor de la expresión que acaba de escribir.

Solo mire el rastro de la stack (acorté los caminos para hacerlo legible):

 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 

Como puede ver arriba, la excepción ocurre dentro de inspect , no en Redis.new . Cuando llama a inspect en un objeto Redis, en lugar de simplemente imprimir su estado, en realidad hace muchas cosas. En este caso, inspect bashs de conectarse al servidor y lanza una excepción cuando se agote el tiempo. Esto me parece un diseño muy malo y quizás deberíamos presentar un informe de error a los mantenedores de la gem Redis.

Esto lleva a un comportamiento interesante en IRB:

  • Al escribir Redis.new(:host => "google.com") genera una excepción como se muestra arriba
  • Redis.new(:host => "google.com"); 'hello' Redis.new(:host => "google.com"); 'hello' da como resultado ‘ => "hello"

Si desea detectar esta excepción, intente llamar a ensure_connected dentro de su bloque de inicio / rescate / final.