重试连接到速率有限的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 
} 
+0

最后一个对我最合适。谢谢!请注意,您需要编写“tries.dropWhile(\ _。isEmpty).take(1)”,或者您正在取得第一个项目_after_成功连接后(dropWhile从迭代器本身移除一个额外项目,但返回一个迭代器包括那个项目)。 – Steve 2010-08-25 15:15:41

+0

@Steve - 确实。我多么粗心!现在修复。 – 2010-08-25 15:36:56

+1

@Steve - 另外,如果你想要一个最大尝试次数,请注意你可以'try.take(max_number).dropWhile(_。isEmpty).take(1).toList.flatten.headOption'来得到'Some (URLConnection)'或'None',这取决于最大尝试次数是否用尽。 – 2010-08-25 15:44:31