Results 1 to 6 of 6

Thread: How to write a concurrent web service client

  1. #1
    Join Date
    Oct 2008
    Location
    Minneapolis, MN
    Posts
    39

    Default How to write a concurrent web service client

    Hi, I have a requirement to parse a file that contains about 5,000 records and for each record, call a web service. Since each request can take up to 1 minute to get a response back, I would like to make the service calls concurrently. I am honestly not sure where to start and am looking for best practice suggestions.

    Here is how I have defined my spring beans (this actually works):
    Code:
        <bean id="xboxService" class="com.scranthdaddy.xbox.service.XboxServiceImpl">
            <property name="webServiceTemplate" ref="webServiceTemplate"/>
        </bean>
    
        <bean id="marshaller" class="org.springframework.oxm.xmlbeans.XmlBeansMarshaller"/>
    
        <bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
            <property name="defaultUri" value="http://xbox2.scranthdaddy.com"/>
    
            <property name="marshaller" ref="marshaller"/>
    
            <property name="unmarshaller" ref="marshaller"/>
        </bean>
    Thanks!
    Last edited by scranthdaddy; Dec 4th, 2010 at 12:55 PM.

  2. #2
    Join Date
    Oct 2008
    Location
    Minneapolis, MN
    Posts
    39

    Default

    I guess I will answer my own question Hopefully it helps others attempting to do the same thing.

    Here is how I have now defined my spring beans (this actually works):
    Code:
        <bean id="xboxService" class="com.scranthdaddy.xbox.service.XboxServiceImpl">
            <property name="webServiceTemplate" ref="webServiceTemplate"/>
        </bean>
    
        <bean id="messageSender" class="org.springframework.ws.transport.http.CommonsHttpMessageSender">
            <property name="connectionTimeout" value="15000"/>
    
            <property name="readTimeout" value="60000"/>
    
            <property name="maxTotalConnections" value="20"/>
    
            <property name="maxConnectionsPerHost">
                <props>
                    <prop key="*">20</prop>
                </props>
            </property>
        </bean>
    
        <bean id="marshaller" class="org.springframework.oxm.xmlbeans.XmlBeansMarshaller"/>
    
        <bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
            <property name="defaultUri" value="http://xbox2.scranthdaddy.com"/>
    
            <property name="messageSender" ref="messageSender"/>
    
            <property name="marshaller" ref="marshaller"/>
    
            <property name="unmarshaller" ref="marshaller"/>
        </bean>
    My first question: Is calling the xboxService thread-safe and can I call the xboxService concurrently? The answer is yes, because by default the CommonsHttpMessageSender uses HttpClient's MultiThreadedHttpConnectionManager. Just be sure to set the messageSender properties per your requirements.

    My next question: How I do call the xboxService concurrently? The answer was (for my use case) to use some java util concurrent classes:

    Main.java
    Code:
    package com.scranthdaddy;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class Main {
        public static void main(String[] args) throws Exception {
            Main main = new Main();
            main.runBatchThreads();
        }
    
        private void runBatchThreads() {
            // initialize list of WebServiceTask objects
            List<WebServiceTask> webServiceTasks = new ArrayList<WebServiceTask>();
    
            for (int i = 0; i < 5000; i++) {
                WebServiceTask webServiceTask = new WebServiceTask();
    
                webServiceTasks.add(webServiceTask);
            }
    
            System.out.println("Starting threads");
    
            // create ExecutorService to manage threads
            ExecutorService executorService = Executors.newFixedThreadPool(20);
    
            for (WebServiceTask webServiceTask : webServiceTasks) {
                // start thread
                executorService.execute(webServiceTask);
            }
    
            // shutdown worker threads when complete
            executorService.shutdown();
    
            System.out.println("Threads started, main ended");
        }
    }
    WebServiceTask.java
    Code:
    package com.scranthdaddy;
    
    public class WebServiceTask implements Runnable {
        public void run() {
            // call xboxService ...        
        }
    }
    This is really cool because if you use jconsole, you can see the 20 threads started up. And then when then threads are all done they get shutdown. Nice job by the Sun/Oracle developers!
    Last edited by scranthdaddy; Dec 9th, 2010 at 03:36 PM.

  3. #3
    Join Date
    Oct 2006
    Posts
    3

    Default Conurrent web service calls

    Hi, first - thank you for posting your solution!
    I'm to build something similar but without Spring.
    I will have a java client and a java webservice running remotely (I'll be using Axis2). I will also iterate over a large file and will fire asynchronous web service calls.
    I see that you are limiting the calls on the client to 20, right? How did you come up with this number? I'm wondering what is a reasonable number of concurrent web service calls and how to determine it? What happens if you fire too many?
    Would appreciate your comments.
    Thanks
    NK

  4. #4
    Join Date
    Oct 2008
    Location
    Minneapolis, MN
    Posts
    39

    Default

    I see that you are limiting the calls on the client to 20, right? How did you come up with this number? I'm wondering what is a reasonable number of concurrent web service calls and how to determine it? What happens if you fire too many?
    I'm not a threading expert but I understand that if you fire too many threads you could take your server down. I just chose 20 because it was just enough to get the batch completed in a reasonable amount of time. I bought the book Java Concurrency in Practice and there is a formula for determining how many threads to use in your thread pool, but I didn't go by that. Trial and error worked for me, otherwise try posting your question on forums.oracle.com under Java APIs --> Concurrency. Hope that helps!

  5. #5
    Join Date
    Jun 2010
    Posts
    2

    Default

    I've used CommonsHttpMessageSender as a messageSender. But got the below error in a multi threaded environment.

    SimpleHttpConnectionManager being used incorrectly. Be sure that HttpMethod.releaseConnection() is always called and that only one thread and/or method is using this connection manager at a time.

    I see that the constructor of CommonsHttpMessageSender creates an instance of MultiThreadedConn manager but wondering why the SimpleHttpConn manager was used in my case.

    - Priyatham Sundar
    Priyatham Sundar.

  6. #6
    Join Date
    Jun 2010
    Posts
    2

    Default

    Ok. I think I found the issue. My httpSender (CommonsHttpMessageSender) uses a httpClient. This was done to set the proxy host and port. While declaring the httpClient bean (apache commons HttpClient), the httpConnectionManager was not set. (Should have been set to MultiThreadedHttpConnectionManager). Without this , the httpConnectionManager in httpClient defaults to SimpleHttpConnectionManager. This was the issue.

    I've corrected the config to set MultiThreadedHttpConnectionManager as the httpConnectionManager on the httpClient.
    Priyatham Sundar.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •