简体   繁体   English

使用Web服务时避免多次呼叫

[英]Avoiding multiple calls when consuming a web service

I have a task where a user consumes XML from a third party. 我的任务是用户从第三方使用XML。 The XML feed is only updated once a day. XML提要每天仅更新一次。 The XML is stored in a database and returned to the user when requested. XML存储在数据库中,并在请求时返回给用户。 If the XML is not in the database, then it is retrieved from the third party, stored in the database and returned to the user. 如果XML不在数据库中,则从第三方检索它,将其存储在数据库中并返回给用户。 All subsequent requests will simply read the XML from the database. 所有后续请求将仅从数据库中读取XML。

Now my question. 现在我的问题。 Say it takes 10 seconds for the request to the third party to return. 假设返回第三方的请求需要10秒钟。 In this period, there are multiple server calls for the same data. 在此期间,有多个服务器调用同一数据。 I don't want each of these to fire off requests to the third party and I don't want the user to receive nothing or an error. 我不希望这些都触发​​向第三方的请求,也不希望用户什么也不会收到。 They should probably wait for the first request to complete at which point the XML would be available. 他们可能应该等待第一个请求完成,此时XML将可用。 This is a relatively simple problem but I want to know what the best way of catering for it is. 这是一个相对简单的问题,但是我想知道最好的解决方法是什么。

Do I just use a simple flag to control requests or maybe something like a semaphore? 我是否仅使用一个简单的标志来控制请求或信号灯之类的东西? Are there better solutions based on the stack I intend to use which is the Play framework and a cassandra backend. 是否有基于我打算使用的堆栈(Play框架和cassandra后端)更好的解决方案。 Is there something I could do with callbacks or triggers? 有什么我可以做的回调或触发器吗?

By the way, I need to lazy load the data when the first request comes in. So, in this task it isn't an option to get the data in a separate process or when the app starts... 顺便说一句,当第一个请求进入时,我需要延迟加载数据。因此,在此任务中,不能选择在单独的进程中或在应用启动时获取数据。

Thanks 谢谢

All you need to do is create a separate component that is responsible to get the XML from the third party and save it to the database. 您需要做的就是创建一个单独的组件,该组件负责从第三方获取XML并将其保存到数据库中。
In your code the various thread try to "fetch" the XML from this component. 在您的代码中,各种线程尝试从该组件中“获取” XML
This component returns the XML from the database if it exists. 该组件从数据库返回XML (如果存在)。 If it does not exist then you use a ReentrantLock to synchronize. 如果不存在,则使用ReentrantLock进行同步。
So you do a trylock and only one of your threads succeeds. 因此,您进行了一次trylock ,只有一个线程成功。 The rest will be blocked. 其余的将被阻止。 When the lock is released the other threads are unblocked but the XML has already been fetched from the third party and stored to the database by the thread that first managed to gain the lock. 释放锁后,其他线程将被解除阻塞,但XML已从第三方获取并由首先设法获得锁的线程存储到数据库中。 So the other threads just return the XML from the DB. 因此,其他线程仅从数据库返回XML

Example code (this is just a "pseudo code" to get you started. You should handle exceptions etc but the main skeleton can be used. Do NOT forget to unlock in a finally so that your code does not block indefinitelly): 示例代码(。这仅仅是一个“伪代码”,让你开始你应该处理异常等,但可使用的主骨架不要忘记unlockfinally让你的代码不indefinitelly BLOCK):

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM