简体   繁体   中英

Call a Web Service from Servlet at AppEngine

Question: What is best way to call a web service (0.5-1.5 seconds/call) from a servlet at AppEngine? Are blocking calls are scalable at AppEngine environment?

Context: I am developing a web application using AppEngine and J2EE. The applications calls Amazon web service to grab some information for the user. From my asp.net experience, best way to do the calls - is to use async http handler to prevent starvation at IIS thread pool. This feature is not available for J2EE with Servlet 2.5 spec ( 3.0 is planned ).

Right now I am thinking of making my controllers (and servlets) thread safe and request scoped. Is there anything also that I can do? Is it even an issue in J2EE + AppEngine environment?

EDIT: I am aware of AppEngine and JAX-WS async invocation support, but I am not sure how it play with servlet environment. As far as I understand, to complete servlet request, the code still should wait for async WS call completion (callback or whatever). I assume that doing it using synchronization primitives will block current working thread.

So, as far as thread is blocked, to serve another user request servlet container need to allocate new thread in thread pool, allocate new memory for stack and waste time for context switching. Moreover, requests can block entire server, when we run out of threads in thread pool. This assumptions are based on ASP.Net and IIS thread model. Are they applicable to J2EE environment?

ANSWER: After studying Apache and GAE documentation, it seems that starvation of threads in the thread pool is not a real issue. Apache, by default has 200 threads for thread pool (compared to 25 in asp.NET and IIS). Based on this I can infer that threads are rather cheap in JVM.

In case if async processing is really required or servlet container will run out of threads, it's possible to redesign the application to send response via google channel api. The workflow will look like:

  1. Make sync request to servlet
  2. Servlet makes creates channel for async reply and queues task for background worker
  3. Servlet returns response to client
  4. [Serving other requests]
  5. Background worker does processing and pushes data to client via channel api

As you observe, servlets don't support using a single thread to service multiple concurrent requests - one thread is required per request. The best way to do your HTTP call is to use asynchronous urlfetch, and wait on that call to complete when you need the result. This will block the request's thread, but there's no avoiding that - the thread is dedicated to the current request until it terminates no matter what you do.

If you don't need the response from the API call to serve the user's request, you could use the task queue to do the work offline, instead.

使用fetchAsync可以吗?

looks at this, this might help

http://today.java.net/pub/a/today/2006/09/19/asynchronous-jax-ws-web-services.html

I am not sure, If you can exactly replicate what you do in dot net, Here is what you could do to may be to simulate it page on load

  1. Submit an ajax request to controller using a java script body onload
  2. In the controller start the async task and send the response back the user and use a session token to keep track of the task
  3. You can poll the controller (add another method to ask for update of the task, since you have session token to track the task) until u get the response
  4. You can do this either waiting for response page or hidden frame that keeps polling the controller
  5. Once you have the response that you are looking for remove the session token

If you want to do that would be the best option instead of polling would be ideal in this case Reverse Ajax / server push

Edit: Now I understand what you mean, I think you can have your code execute async task not wait for response from async itself, just send response back to the user. I have simple thread that I will start but will wait for it to finish as I send the response back to the user and the same time use a session token to track the request

@Controller
@RequestMapping("/asyncTest")
public class AsyncCotroller {
@RequestMapping(value = "/async.html", method = RequestMethod.GET)
public ModelAndView dialogController(Model model, HttpServletRequest request) 
{
   System.err.println("(System.currentTimeMillis()/1000) " + (System.currentTimeMillis()/1000));
   //start a thread (async simulator)
   new Thread(new MyRunnbelImpl()).start();
   //use this attribute to track response
   request.getSession().setAttribute("asyncTaskSessionAttribute", "asyncTaskSessionAttribute");
       //if you look at the print of system out, you will see that it is not waiting on //async task
   System.err.println("(System.currentTimeMillis()/1000) " + (System.currentTimeMillis()/1000));
   return new ModelAndView("test");
}

class MyRunnbelImpl implements Runnable
{

    @Override
    public void run() 
    {
        try 
        {
            Thread.sleep(5000);
        } catch (InterruptedException e) 
        {
            e.printStackTrace();
        }
    }

}
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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