重试连接到速率有限的URL,直到在Scala中成功为止
问题描述:
我需要对速率有限的REST api进行GET调用。我可以通过拨打电话并检查HTTP标头来了解当前的限制速率。如果我超过了我的费率限制,我应该等一会再重试。我想写类似:重试连接到速率有限的URL,直到在Scala中成功为止
val conn = connect(url, _.getHeaderField("X-RateLimit-Remaining").toInt > 0, 500)
我有使用VAR,while循环和一些重复的代码工作的解决方案,但感觉笨重:
def connect(url: String, succeeded: URLConnection=>Boolean, waitMillis: Int) = {
var conn = new URL(url).openConnection
while (!succeeded(conn)) {
Thread.sleep(waitMillis)
conn = new URL(url).openConnection
}
conn
}
有一个更清洁的方式去做这个?
答
你可以把尾递归:
def connect(url: String, succeeded: URLConnection=>Boolean, wait: Int): URLConnection = {
val conn = new URL(url).openConnection
if (succeeded(conn)) conn
else {
Thread.sleep(wait)
connect(url,succeeded,wait)
}
}
或者你可以使用无限迭代器模式,无论是原料:
def connect(url: String, succeeded: URLConnection=>Boolean, waitMillis: Int) = {
val tries = Iterator.continually(new URL(url).openConnection)
tries.dropWhile(
conn => if (succeeded(conn)) false else { Thread.sleep(waitMillis); true }
).next
}
或包裹在等待返回一个网址通话选项(如果你想选择其他地方的处理特别有用,不知道是否要嵌入那里等候或外部):
def attemptConnect(url: String, succeeded: URLConnection=>Boolean, waitMillis: Int) = {
val conn = new URL(url).openConnection
if (succeeded(conn)) Some(conn)
else { Thread.sleep(waitMillis); None }
}
def connect(url: String, succeeded: URLConnection=>Boolean, waitMillis: Int) = {
val tries = Iterator.continually(attemptConnect(url,succeeded,waitMillis))
tries.dropWhile(_.isEmpty).next
}
最后一个对我最合适。谢谢!请注意,您需要编写“tries.dropWhile(\ _。isEmpty).take(1)”,或者您正在取得第一个项目_after_成功连接后(dropWhile从迭代器本身移除一个额外项目,但返回一个迭代器包括那个项目)。 – Steve 2010-08-25 15:15:41
@Steve - 确实。我多么粗心!现在修复。 – 2010-08-25 15:36:56
@Steve - 另外,如果你想要一个最大尝试次数,请注意你可以'try.take(max_number).dropWhile(_。isEmpty).take(1).toList.flatten.headOption'来得到'Some (URLConnection)'或'None',这取决于最大尝试次数是否用尽。 – 2010-08-25 15:44:31