通过ruby OpenURI下载文件时出现间歇性EOFError

Posted

技术标签:

【中文标题】通过ruby OpenURI下载文件时出现间歇性EOFError【英文标题】:Intermittant EOFError when downloading file via ruby OpenURI 【发布时间】:2013-06-15 11:58:24 【问题描述】:

我有一个设置,其中 cron 作业定期从外部服务 (Twilio) 下载 mp3 文件,然后使用 Paperclip 将文件上传到 Amazon S3。该过程由 Resque 在后台处理。

以下是处理从 Twilio 下载和随后附加到 Paperclip 的代码:

# Perform transfer from Twilio to S3
def self.perform(group_recording_id = nil)
  gr = GroupRecording.find(group_recording_id)
  # ...
  recording = TwilioClient.account.recordings.get(gr.external_id)

  if recording.present?
    # ....
    gr.audio_file = download_remote_file(gr.twilio_mp3_url)
    gr.save
  end
end

def download_remote_file(url)
  io = open(URI.parse(url))  

  # overrides Paperclip::Upfile#original_filename
  def io.original_filename
    base_uri.path.split('/').last
  end
  io.original_filename.blank? ? nil : io
end

EOFErrors 失败:

EOFError
end of file reached
/usr/local/lib/ruby/1.9.1/openssl/buffering.rb:145:in `sysread_nonblock'
/usr/local/lib/ruby/1.9.1/openssl/buffering.rb:145:in `read_nonblock'
/usr/local/lib/ruby/1.9.1/net/protocol.rb:135:in `rbuf_fill'
/usr/local/lib/ruby/1.9.1/net/protocol.rb:116:in `readuntil'
/usr/local/lib/ruby/1.9.1/net/protocol.rb:126:in `readline'
/usr/local/lib/ruby/1.9.1/net/http.rb:2219:in `read_status_line'
/usr/local/lib/ruby/1.9.1/net/http.rb:2208:in `read_new'
/usr/local/lib/ruby/1.9.1/net/http.rb:1191:in `transport_request'
/usr/local/lib/ruby/1.9.1/net/http.rb:1177:in `request'
/app/vendor/bundle/ruby/1.9.1/gems/rest-client-1.6.7/lib/restclient/net_http_ext.rb:51:in `request'
/usr/local/lib/ruby/1.9.1/open-uri.rb:312:in `block in open_http'
/usr/local/lib/ruby/1.9.1/net/http.rb:627:in `start'
/usr/local/lib/ruby/1.9.1/open-uri.rb:306:in `open_http'
/usr/local/lib/ruby/1.9.1/open-uri.rb:769:in `buffer_open'
/usr/local/lib/ruby/1.9.1/open-uri.rb:203:in `block in open_loop'
/usr/local/lib/ruby/1.9.1/open-uri.rb:201:in `catch'
/usr/local/lib/ruby/1.9.1/open-uri.rb:201:in `open_loop'
/usr/local/lib/ruby/1.9.1/open-uri.rb:146:in `open_uri'
/usr/local/lib/ruby/1.9.1/open-uri.rb:671:in `open'
/usr/local/lib/ruby/1.9.1/open-uri.rb:33:in `open'
/app/app/models/group_recording.rb:112:in `download_remote_file'
/app/app/models/group_recording.rb:85:in `perform'

上面是最常见的错误,但我也遇到了这个:

Errno::ECONNRESET
Connection reset by peer
/app/vendor/ruby-1.9.2/lib/ruby/1.9.1/openssl/buffering.rb:145:in `sysread_nonblock'
/app/vendor/ruby-1.9.2/lib/ruby/1.9.1/openssl/buffering.rb:145:in `read_nonblock'
/app/vendor/ruby-1.9.2/lib/ruby/1.9.1/net/protocol.rb:135:in `rbuf_fill'
/app/vendor/ruby-1.9.2/lib/ruby/1.9.1/net/protocol.rb:86:in `read'
/app/vendor/ruby-1.9.2/lib/ruby/1.9.1/net/http.rb:2424:in `read_body_0'
/app/vendor/ruby-1.9.2/lib/ruby/1.9.1/net/http.rb:2379:in `read_body'
/app/vendor/ruby-1.9.2/lib/ruby/1.9.1/open-uri.rb:321:in `block (2 levels) in open_http'
/app/vendor/ruby-1.9.2/lib/ruby/1.9.1/net/http.rb:1194:in `block in transport_request'
/app/vendor/ruby-1.9.2/lib/ruby/1.9.1/net/http.rb:2342:in `reading_body'
/app/vendor/ruby-1.9.2/lib/ruby/1.9.1/net/http.rb:1193:in `transport_request'
/app/vendor/ruby-1.9.2/lib/ruby/1.9.1/net/http.rb:1177:in `request'
/app/vendor/bundle/ruby/1.9.1/gems/rest-client-1.6.7/lib/restclient/net_http_ext.rb:51:in `request'
/app/vendor/ruby-1.9.2/lib/ruby/1.9.1/open-uri.rb:312:in `block in open_http'
/app/vendor/ruby-1.9.2/lib/ruby/1.9.1/net/http.rb:627:in `start'
/app/vendor/ruby-1.9.2/lib/ruby/1.9.1/open-uri.rb:306:in `open_http'
/app/vendor/ruby-1.9.2/lib/ruby/1.9.1/open-uri.rb:769:in `buffer_open'
/app/vendor/ruby-1.9.2/lib/ruby/1.9.1/open-uri.rb:203:in `block in open_loop'
/app/vendor/ruby-1.9.2/lib/ruby/1.9.1/open-uri.rb:201:in `catch'
/app/vendor/ruby-1.9.2/lib/ruby/1.9.1/open-uri.rb:201:in `open_loop'
/app/vendor/ruby-1.9.2/lib/ruby/1.9.1/open-uri.rb:146:in `open_uri'
/app/vendor/ruby-1.9.2/lib/ruby/1.9.1/open-uri.rb:671:in `open'
/app/vendor/ruby-1.9.2/lib/ruby/1.9.1/open-uri.rb:33:in `open'
/app/app/models/group_recording.rb:113:in `download_remote_file'
/app/app/models/group_recording.rb:86:in `perform'

这个问题是间歇性的,最近才开始在heroku的生产环境中出现,相关代码没有任何变化。该应用程序目前在 heroku 上的 ruby 1.9.3-p429 上。该问题也发生在本地,但频率较低。我尝试了相同且更低的 ruby​​ 版本(低至 1.9.3-p194)。

有人遇到过类似的问题吗?在线搜索错误发现了类似的错误,但在完全不同的上下文中。

【问题讨论】:

会不会是文件的源站禁止了你的代码? “Errno::ECONNRESET”表示他们关闭了连接。我认为 EOF 错误会指向类似的问题,即在您收到所有预期内容之前文件被截断。 感谢您的评论。有问题的网站是 Twilio。网站所有者的 cc 存档最近确实过期了,但他很快就更新了它。无论如何,为什么错误会是间歇性的,而且并非总是如此? 由于多种原因,它可能是间歇性的。如果没有关于他们的系统和流程的内部信息,任何所说的都是纯粹的猜测。我们的网络中有一些我们称之为“生物”的东西,它们有时无法一致地输入命令,无法将规则应用于所有设备。 嗯,我想接下来会讨论 Twilio 的问题。感谢您为我指明这个方向。 不知道 Twilio,这完全是在黑暗中拍摄:recordings.get() 函数是否有可能是异步的?即,它在服务器上的实际位可用之前返回一个记录对象?连续运行两次是否出现错误? 【参考方案1】:

这些是您在代码中应该预料到的暂时性网络错误,然后重试该操作(通常在短暂休眠后)。互联网不可靠!

您应该记录重试,如果您发现峰值或异常模式,您可能需要与您的服务提供商(heroku、twilio 等)联系,因为他们可以提供洞察力。

您无法直接从代码中解决问题(如果确实没有改变的话)。

【讨论】:

以上是关于通过ruby OpenURI下载文件时出现间歇性EOFError的主要内容,如果未能解决你的问题,请参考以下文章

通过 Obj-c 查询 REST API 时出现 Azure DocumentDB 间歇性 401 错误

连接到 JIRA 时出现间歇性 102 错误 (ERR_CONNECTION_REFUSED)

IBM MFP - 身份验证时出现间歇性 SocketTimeoutException

调用 GMAIL API 时出现间歇性错误 - “调用者没有权限”

访问存储的 Proc 输出参数时出现间歇性空引用错误

在谷歌浏览器上下载大文件(最大 15 mb)时出现问题