当我添加超时块时,我开始发生undefined local variable or method `page'
:
begin
Timeout::timeout(30) do
page = Nokogiri::HTML(open(url))
end
rescue Timeout::Error
Rollbar.error("Timeout on #{url}")
return
end
# other code using page
我的Timeout代码/救援有问题吗?
答案 0 :(得分:2)
块中定义的变量的范围限定为各自的块。例如:
1.times do
some_var = 1
p some_var # Prints 1
end
p some_var # Will throw an error
如果要将变量范围扩大到更高的上下文,则必须在块外部定义它:
some_var = nil
1.times do
some_var = 1
p some_var # Prints 1
end
p some_var # Prints 1
在你的情况下:
page = nil # Define the scope of the variable up here
begin
Timeout::timeout(30) do
page = Nokogiri::HTML(open(url)) # Now set that variable
end
rescue Timeout::Error
Rollbar.error("Timeout on #{url}")
return
end
# other code using page
答案 1 :(得分:2)
首先:问题与您的begin/rescue/end
阻止无关,所以让我们暂时删除异常处理:
Timeout::timeout(30) do
page = Nokogiri::HTML(open(url))
end
page #=> undefined local variable or method `page'
这是因为do/end
块创建了新的variable scope和
(...)在其中创建的任何局部变量都不会泄漏到周围的范围。
您可以在块之外(即之前)定义page
:
page = nil
Timeout::timeout(30) do
page = Nokogiri::HTML(open(url))
end
page #=> #<Nokogiri::HTML::Document...>
但还有其他选择。
如果您阅读了Timeout::timeout
的文档,则会注意到它会返回该块的结果。所以你可以写:
page = Timeout::timeout(30) { Nokogiri::HTML(open(url)) }
OpenURI::OpenRead#open
的文档也很有趣。它揭示了您可以将多个选项传递给open
,特别是:
<强>
:read_timeout
强>:read_timeout选项指定http连接的读取超时。
<强>
:open_timeout
强>:open_timeout选项指定http连接的打开超时。
[有关详情,请参阅Net::HTTP#open_timeout
和Net::HTTP#read_timeout
假设url
是HTTP网址,您可以将timeout
来电替换为:
begin
page = Nokogiri::HTML(open(url, open_timeout: 30, read_timeout: 30))
rescue Timeout::Error
Rollbar.error("Timeout on #{url}")
return
end
或更具体:
begin
page = Nokogiri::HTML(open(url, open_timeout: 30, read_timeout: 30))
rescue Net::ReadTimeout
Rollbar.error("Timeout reading #{url}")
return
rescue Net::OpenTimeout
Rollbar.error("Timeout opening #{url}")
return
end
请注意,begin
不创建新的变量范围。
答案 2 :(得分:1)
变量page
仅在timeout
块中可见。您可以在阻止之前初始化page
,例如page = nil
或封装了方法中page
值的检索。
def retrieve(url2)
Timeout::timeout(30) do
Nokogiri::HTML(open(url2))
end
rescue Timeout::Error
Rollbar.error("Timeout on #{url2}")
nil
end
page = retrieve(url)