Ruby &引用;救援例外情况“;未营救超时::net_http中的错误
我们似乎遇到了这样一种情况,Ruby &引用;救援例外情况“;未营救超时::net_http中的错误,ruby,exception-handling,rescue,Ruby,Exception Handling,Rescue,我们似乎遇到了这样一种情况,救援异常未捕获特定异常 我正在尝试发送有关发生的任何异常的电子邮件警报,然后继续处理。我们已经对有意退出进行了必要的处理。我们希望循环在警告我们之后继续运行,以防发生任何其他情况 根据堆栈跟踪,未被捕获的异常表面上是Timeout::Error 这是堆栈跟踪,删除了对中间代码的引用(代码的最后一行是request.rb:93): 这是request.rb#send,第93行带有注释: def send build uri = URI.parse(
救援异常
未捕获特定异常
我正在尝试发送有关发生的任何异常的电子邮件警报,然后继续处理。我们已经对有意退出进行了必要的处理。我们希望循环在警告我们之后继续运行,以防发生任何其他情况
根据堆栈跟踪,未被捕获的异常表面上是Timeout::Error
这是堆栈跟踪,删除了对中间代码的引用(代码的最后一行是request.rb:93):
这是request.rb#send,第93行带有注释:
def send
build
uri = URI.parse([DST::Request.configuration[:prefix], @path].join('/'))
https = Net::HTTP.new(uri.host, uri.port)
https.use_ssl = true
https.verify_mode = OpenSSL::SSL::VERIFY_NONE
https_request = Net::HTTP::Post.new(uri.request_uri.tap{|e| debug_puts "\nURL: #{e}, host:#{uri.host}"})
# line 93:
https_request.body = request
response = https.request(https_request)
# the rest should be irrelevant
这里是dst_daemon.rb;第49行用注释表示,应该捕获除故意中断以外的任何内容的救援异常
接近尾声:
DST::Request.environment = :production
class DST::Request::RequestFailed < Exception; end
Thread.abort_on_exception = true
SEMAPHORE = 'import/dst/start.txt' unless defined?(SEMAPHORE)
DEBUG_DST = 'import/dst/debug.txt' unless defined?(DEBUG_DST)
DEBUG_LOG = 'import/dst/debug.log' unless defined?(DEBUG_LOG)
def debug_dst(*args)
File.open(DEBUG_LOG, 'a') do |f|
f.print "#{Time.now.localtime}: "
f.puts(*args)
end if debug_dst?
end
def debug_dst?
File.exist?(DEBUG_DST)
end
dst_ids = [Institution::BAA_DST_WS_CLIENT_ID, Institution::BAA_DST_WS_DEALER_ID]
institutions = Institution.find_all_by_baa_api_financial_institution_id(dst_ids)
DST::Collector.prime_key!
loop do
begin
if File.exist?(SEMAPHORE)
debug_dst 'waking up...'
custodians = InstitutionAccount.acts_as_baa_custodian.
find_all_by_institution_id(institutions).select(&:direct?)
good,bad = custodians.partition do |c|
c.custodian_users.map{|e2|e2.custodian_passwords.count(:conditions => ['expired is not true']) == 1}.all?
end
if bad.present?
msg = " skipping: \n"
bad.each do |c|
msg += " #{c.user.full_name_or_email}, custodian id #{c.id}: "
c.custodian_users.each{|cu| msg += "#{cu.username}:#{cu.custodian_passwords.count(:conditions => ['expired is not true'])}; "}
msg += "\n"
end
AdminSimpleMailer.deliver_generic_mail("DST Daemon skipping #{bad.size} connections", msg)
debug_dst msg
end
Benchmark.measure do
good.each do |custodian|
begin
debug_dst " collecting for: #{custodian.name}, #{custodian.subtitle}, (#{custodian.id.inspect})"
# line 49:
DST::Collector.new(custodian, 0).collect!
rescue DST::Request::PasswordFailed, DST::Request::RequestFailed => e
message = e.message + "\n\n" + e.backtrace.join("\n")
AdminSimpleMailer.deliver_generic_mail("DST Daemon Connection Failed #{e.class.name}", message)
debug_dst " skipping, #{e.class}"
end
end
end.tap{|duration| debug_dst "collection done, duration #{duration.real.to_f/60} minutes. importing" }
DST::Strategy.new(Date.yesterday, :recompute => true).import!
debug_dst 'import done.'
rm SEMAPHORE, :verbose => debug_dst?
else
debug_dst 'sleeping.' if Time.now.strftime("%M").to_i % 5 == 0
end
rescue SystemExit, Interrupt
raise
rescue Exception => e
message = e.message + "\n\n" + e.backtrace.join("\n")
AdminSimpleMailer.deliver_generic_mail("DST Daemon Exception #{e.class.name}", message)
ensure
sleep 60
end
end
DST::Request.environment=:生产
类DST::Request::RequestFailed<异常;结束
Thread.abort_on_异常=true
信号量='import/dst/start.txt',除非已定义?(信号量)
DEBUG_DST='import/DST/DEBUG.txt',除非已定义?(DEBUG_DST)
调试日志='import/dst/DEBUG.LOG',除非已定义?(调试日志)
def debug_dst(*args)
打开(调试日志,'a')do | f|
f、 打印“#{Time.now.localtime}:”
f、 puts(*args)
是否在调试时结束?
结束
def调试测试?
文件.exist?(调试测试)
结束
dst_ID=[机构::BAA_dst_WS_客户ID,机构::BAA_dst_WS_经销商ID]
机构=机构。按机构id(dst id)查找所有机构
DST::Collector.prime_键!
环道
开始
如果文件.exist?(信号量)
调试dst“唤醒…”
保管人=机构账户。作为保管人。
按机构id查找所有机构。选择(&:直接?)
好的,坏的=保管人|
c、 保管人用户.map{e2 | e2.保管人密码.count(:conditions=>['expired is not true'])==1}。全部?
结束
如果不好的话,现在呢?
msg=“正在跳过:\n”
不好,每个都可以|
msg+=“#{c.user.全名或电子邮件},保管人id#{c.id}:”
c、 保管人用户。每个{cu124; msg+=“{cu.username}:{cu.保管人密码.count(:conditions=>['expired is not true']))};”
msg+=“\n”
结束
AdminSimpleEmailer.deliver_generic_mail(“DST守护进程跳过#{bad.size}连接”,msg)
调试消息
结束
基准测试
好的,每个人都有监护人|
开始
debug#u dst“为以下对象收集:#{保管人.name},#{保管人.subtitle},(#{保管人.id.inspect})”
#第49行:
DST::Collector.new(保管人,0)。collect!
rescue DST::Request::PasswordFailed,DST::Request::RequestFailed=>e
message=e.message+“\n\n”+e.backtrace.join(“\n”)
AdminSimpleEmailer.deliver_generic_mail(“DST守护程序连接失败#{e.class.name}”,消息)
调试“跳过,{e.class}”
结束
结束
end.tap{| duration | debugdst“收集完成,duration{duration.real.to_f/60}分钟。导入”}
DST::Strategy.new(Date.dayed,:recompute=>true)。导入!
调试dst“导入完成”
rm信号量:verbose=>debugdst?
其他的
调试\u dst'sleeping.'if Time.now.strftime(“%M”).to \u i%5==0
结束
救援系统退出,中断
提升
救援异常=>e
message=e.message+“\n\n”+e.backtrace.join(“\n”)
AdminSimpleEmailer.deliver_generic_mail(“DST守护进程异常#{e.class.name}”,消息)
确保
睡60
结束
结束
除了从SystemExit或Interrupt退出之外,是否不可能使用堆栈跟踪退出此循环?您可能已经知道,在rescue块内调用
raise
将向调用方引发异常。
由于在ruby 1.8*中,Timeout::Error
是一个中断
,因此net_http引发的超时异常将在rescue SystemExit,INTERRUP
块中处理,而不是在下面的rescue exception=>e
中处理
要验证Timeout::Error
是否为中断,只需计算Timeout::Error.exe
。从中得到的是Timeout::Error继承自的类的层次结构
*ruby1.9中不再是这种情况。在代码中,实际引发的异常在哪里?堆栈跟踪中没有一行与我看到的任何内容对应。它实际上是在引发一个
Timeout::Error
,它确实继承了异常
。我根本无法重现此问题。我在代码示例中添加了一条注释这是引发异常的代码
(尽管我拼写“exception”错误-已修复。我将很快重新发布此问题,现在我发现为了简洁起见,我过度编辑了原始情况。我道歉。我发现异常默认为Class.new(ExitException)…无论如何,当我在控制台中尝试此操作时,exception.class是class,exception.class.parent是object。class.new(ExitException)
将实际创建一个从ExitexException
继承的匿名类。当然异常。类
就是类。这同样适用于异常。类
,对吗?你真正想要的是异常。祖先
。这将证明异常是异常的子类。我已经重写了这个问题。我如果有人认为最好删除并重新发布b/c,请告知。顺便说一句,这意味着解决您问题的简单方法是在救援系统退出之前添加一个显式救援超时::Error
块,在dst_守护进程中中断一个。rbAwesome,非常感谢您-我没有想到要查看Timeout::错误源自我显式捕获的一个异常。
DST::Request.environment = :production
class DST::Request::RequestFailed < Exception; end
Thread.abort_on_exception = true
SEMAPHORE = 'import/dst/start.txt' unless defined?(SEMAPHORE)
DEBUG_DST = 'import/dst/debug.txt' unless defined?(DEBUG_DST)
DEBUG_LOG = 'import/dst/debug.log' unless defined?(DEBUG_LOG)
def debug_dst(*args)
File.open(DEBUG_LOG, 'a') do |f|
f.print "#{Time.now.localtime}: "
f.puts(*args)
end if debug_dst?
end
def debug_dst?
File.exist?(DEBUG_DST)
end
dst_ids = [Institution::BAA_DST_WS_CLIENT_ID, Institution::BAA_DST_WS_DEALER_ID]
institutions = Institution.find_all_by_baa_api_financial_institution_id(dst_ids)
DST::Collector.prime_key!
loop do
begin
if File.exist?(SEMAPHORE)
debug_dst 'waking up...'
custodians = InstitutionAccount.acts_as_baa_custodian.
find_all_by_institution_id(institutions).select(&:direct?)
good,bad = custodians.partition do |c|
c.custodian_users.map{|e2|e2.custodian_passwords.count(:conditions => ['expired is not true']) == 1}.all?
end
if bad.present?
msg = " skipping: \n"
bad.each do |c|
msg += " #{c.user.full_name_or_email}, custodian id #{c.id}: "
c.custodian_users.each{|cu| msg += "#{cu.username}:#{cu.custodian_passwords.count(:conditions => ['expired is not true'])}; "}
msg += "\n"
end
AdminSimpleMailer.deliver_generic_mail("DST Daemon skipping #{bad.size} connections", msg)
debug_dst msg
end
Benchmark.measure do
good.each do |custodian|
begin
debug_dst " collecting for: #{custodian.name}, #{custodian.subtitle}, (#{custodian.id.inspect})"
# line 49:
DST::Collector.new(custodian, 0).collect!
rescue DST::Request::PasswordFailed, DST::Request::RequestFailed => e
message = e.message + "\n\n" + e.backtrace.join("\n")
AdminSimpleMailer.deliver_generic_mail("DST Daemon Connection Failed #{e.class.name}", message)
debug_dst " skipping, #{e.class}"
end
end
end.tap{|duration| debug_dst "collection done, duration #{duration.real.to_f/60} minutes. importing" }
DST::Strategy.new(Date.yesterday, :recompute => true).import!
debug_dst 'import done.'
rm SEMAPHORE, :verbose => debug_dst?
else
debug_dst 'sleeping.' if Time.now.strftime("%M").to_i % 5 == 0
end
rescue SystemExit, Interrupt
raise
rescue Exception => e
message = e.message + "\n\n" + e.backtrace.join("\n")
AdminSimpleMailer.deliver_generic_mail("DST Daemon Exception #{e.class.name}", message)
ensure
sleep 60
end
end