我有一个用户从第三方使用XML的任务。 XML Feed仅每天更新一次。 XML存储在数据库中,并在请求时返回给用户。如果XML不在数据库中,则从第三方检索它,存储在数据库中并返回给用户。所有后续请求都只是从数据库中读取XML。
现在我的问题。假设请求第三方返回需要10秒钟。在此期间,对同一数据有多个服务器调用。我不希望其中的每一个都向第三方发出请求,我不希望用户收到任何内容或错误。他们应该等待第一个请求完成,此时XML将可用。这是一个相对简单的问题,但我想知道最好的方式是什么。
我只是使用一个简单的标志来控制请求或者像信号量这样的东西吗?是否有更好的解决方案基于我打算使用的堆栈,即Play框架和cassandra后端。我可以用回调或触发器做些什么吗?
顺便说一句,我需要在第一个请求进入时延迟加载数据。因此,在此任务中,不能选择在单独的进程中或应用程序启动时获取数据......
由于
答案 0 :(得分:1)
您需要做的就是创建一个单独的组件,负责从第三方获取XML
并将其保存到数据库中。
在您的代码中,各个线程尝试从此组件“获取”XML
此组件从数据库返回XML
(如果存在)。如果它不存在,则使用ReentrantLock进行同步
所以你做trylock并且只有一个线程成功。其余的将被阻止。释放锁时,其他线程将被解除阻塞,但XML
已从第三方获取并由首先设法获得锁定的线程存储到数据库。所以其他线程只返回数据库中的XML
。
示例代码(这只是一个“伪代码”,可以帮助您入门。您应该处理异常等但可以使用主骨架。 NOT 忘记unlock
finally
以便您的代码不会无限制地阻止):
public String getXML() {
String xml = getXMLFromDatabase();
if(xml == null) {
if(glocalLock.tryLock()) {
try{
xml = getXMLFromThirdParty();
storeXMLToDatabase(xml);
}
finally {
globalLock.unlock(); //ok! got XML and stored in DB. Wake-up others!
}
}
else {
try{ //Another thread got the lock and will do the query. Just wait on lock!
globalLock.lock();
}
finally {
//woken up but the xml is already fetched
xml = getXMLFromDatabase();
globalLock.unlock();
}
}
return xml;
}