3

I had a need to limit the connection rate (in my servlet) to certain external service and I decided to give ScheduledExecutorService a try. Scheduling itself seems to function just fine, but output gets printed only occasionally - in most cases nothing is outputted. Why does such happen? I'm using Tomcat 7 as a test server.

int waitingtimeinmilliseconds = 5000;

ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();

ScheduledFuture scheduledFuture = scheduledExecutorService.schedule() {

    public void run() {

        Fetcher fetcher = new Fetcher(loginname, password);
        List<Item> items = fetcher.fetchItems();
        // do something with the results

        //ServletOutputStream
        out.print("teststring" + items.size());

    }

}, waitingtimeinmilliseconds, TimeUnit.MILLISECONDS);
scheduledExecutorService.shutdown();
  • why not simple Thread.sleep(5000) – irreputable Oct 08 '12 at 22:04
  • Variable 'waitingtimeinmilliseconds' is actually generated by a filter. It will take care that there is always atleast certain amount of time between two connections to an external service (one external service access per servlet thread). – Marko Seppänen Oct 08 '12 at 22:17

1 Answers1

2

You'll find very exhaustive description of what is causing your problem in: HttpServletResponse seems to periodically send prematurely (also check: starting a new thread in servlet).

Basically you cannot use external threads to write to servlet output. Once you leave doGet()/doPost(), servlet container assumes you are done and discards the output after flushing it to the client. But since you are writing to the stream asynchronously, sometimes the output gets through, while other times gets discarded.

If you want your rate limiting to be very scalable, consider async servlets (from 3.0). If you just want to throttle some clients, RateLimiter from will work for you1.

1 - see RateLimiter - discovering Google Guava on my blog.

Community
  • 1
  • 1
Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
  • Thank you. I'll take a look at that post. I just noticed that if the servlet doesn't seem to output anything for my AJAX-based GUI to consume, I might see the wanted output right before , if I refresh the browser. Later I might have to choose a PaaS-provider, which doesn't support Tomcat 7 (just Tomcat 6), which support only Servlet spesification 2.5, but I will seriously consider using asyncronous servlets. – Marko Seppänen Oct 08 '12 at 22:11
  • I now understand that it was about race condition. However, by using asyncronous servlets and outputting inside AsyncListeners's onComplete-method I am now left with a situation, where everything functions just fine (output is always exactly what is suppose to be). I'd like add that it wasn't enough to add "asyncSupported = true" to the WebServlet-annotation. I had to set following attribute: req.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", true); – Marko Seppänen Oct 09 '12 at 16:11
  • Here's simple example about using asyncronous servlets (very useful feature): http://developerlife.com/tutorials/?p=1437 – Marko Seppänen Oct 09 '12 at 16:13
  • @MarkoSeppänen: I never had to use this special attribute, however I found [this](http://stackoverflow.com/questions/7855712). Note that once you started async processing you can write to `OutputStream` at any time from any thread. Not necessarily from `onComplete()`. – Tomasz Nurkiewicz Oct 09 '12 at 16:15