首页 文章

在使用Web服务时避免多次调用

提问于
浏览
0

我有一个任务,用户从第三方使用XML . XML Feed仅每天更新一次 . XML存储在数据库中,并在请求时返回给用户 . 如果XML不在数据库中,则从第三方检索它,存储在数据库中并返回给用户 . 所有后续请求都只是从数据库中读取XML .

现在我的问题 . 假设请求第三方返回需要10秒钟 . 在此期间,对同一数据有多个服务器调用 . 我不希望其中的每一个都向第三方发出请求,我不希望用户收到任何内容或错误 . 他们应该等待第一个请求完成,此时XML将可用 . 这是一个相对简单的问题,但我想知道最好的方式是什么 .

我只是使用一个简单的标志来控制请求或者像信号量这样的东西吗?是否有更好的解决方案基于我打算使用的堆栈,即Play框架和cassandra后端 . 我可以用回调或触发器做些什么吗?

顺便说一句,我需要在第一个请求进入时延迟加载数据 . 因此,在此任务中,不能选择在单独的进程中或应用程序启动时获取数据...

谢谢

1 回答

  • 1

    您需要做的就是创建一个单独的组件,负责从第三方获取 XML 并将其保存到数据库中 .
    在您的代码中,各个线程尝试从此组件"fetch" XML .
    此组件从数据库返回 XML (如果存在) . 如果它不存在则使用ReentrantLock进行同步 .
    所以你做了trylock并且只有一个线程成功 . 其余的将被阻止 . 当释放锁时,其他线程被解除阻塞,但 XML 已经从第三方获取并由首先设法获得锁定的线程存储到数据库 . 所以其他线程只是从DB返回 XML .

    示例代码(这只是一个"pseudo code"来帮助你开始 . 你应该处理异常等但是可以使用主骨架 . 在 finally 中忘记 unlock 以便你的代码不会阻止无限制):

    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;  
    }
    

相关问题