0

A non-static method in a class sends an HTTP get request that frequently "hangs" (waits forever for a response); in order to cut it after a certain timeout, I use a Timer as shown in this SO question.

Every time the method is called and the get is initiated, I expect the timer to start from scratch.

But that's not what happens; what happens is the timer starts the first time the method is called, and continues to run for the duration of the execution of the whole program; and when it times out, it aborts whatever get request is currently running.

Here's my code (simplified):

public void processRequest() throws Exception {
  final HttpClient client = HttpClientBuilder.create().build();
  final String target = this.someString;
  final int timeout = 10;
  HttpGet get = new HttpGet(target);

  Timer timer = new Timer();
  timer.schedule(new TimerTask() {
    public void run() {
      try {
        get.abort();
        // if the request times out it probably means
        // the server is down so we exit the program
        // and don't run any more requests
        System.exit(1);
        }
     catch (Exception e) {
        // warn that something went wrong
        }
      }
    }, timeout * 1000);
  //Execute and get the response
  final HttpResponse response = client.execute(get);
  final int code = response.getStatusLine().getStatusCode();
  if (code == 200) {
    // do something with the response, etc.
    }
  }

processRequest is called once for each instance of the class it belongs to; after the first call, the program exits after the duration of timeout.

Edit: or maybe it's the first timer that continues to run, and I need to kill it when I receive the get response?

Edit2: ok, that solves it: adding timer.cancel() when the response is received avoids the problem. But I don't understand why! get is relative to one instance; how is it possible for a timer coming from a previous instance to abort a get that belongs to another instance?

Community
  • 1
  • 1
Bambax
  • 2,920
  • 6
  • 34
  • 43
  • System.exit(1); will turn down your whole application. – dinesh707 Oct 28 '13 at 10:46
  • Yes, that's what we want; if we have a timeout on any request, it almost certainly means the server is down. And so we don't want to continue the program because doing so would send more requests to a server that is down. We need to call someone to bring the server back up. – Bambax Oct 28 '13 at 10:49
  • 1
    Do you ever cancel the timer after the response you want? – arcy Oct 28 '13 at 10:55
  • use a "ArrayBlockingQueue(1)". The way your doing it will any way kill your application after 10 seconds. – dinesh707 Oct 28 '13 at 10:55
  • @rcook, no, that was my problem! ;-) But it's still not clear how a timer from a given instance can kill a request from another instance. – Bambax Oct 28 '13 at 11:02
  • I'm not all that familiar with the TimerTask, but the 'run' method implies that it is started in a different thread, and therefore the thread would have its own reference to the timer. In that case, even if the 'current instance' went out of scope, the thread would have its own instance, and the timer would still be out there timing. Incidentally, as an alternative to killing it, you could have it test that the request had completed before it did anything drastic. Also, I think having it exit the program like that is too drastic; no message logged anywhere, nothing? – arcy Oct 28 '13 at 11:22
  • @rcook yes, there are a lot of log messages but I took them out before posting; your other suggestion to test what's happening with the request before killing it interesting... would it be possible to test whether it's the same request or another one? – Bambax Oct 28 '13 at 11:28
  • As far as I know, sure - init response to null, create HttpResponseTimeoutCheck which extends TimerTask, make HRTC's only constructor one that takes the response as a parameter. HRTC's constructor stores the response reference as an instance variable. When the timer fires, HRTC checks the response to see if it's still null; if it isn't, then someone filled it in and the timer can simply exit. If it's still null, the response didn't get filled in, and the request has therefore timed out. – arcy Oct 28 '13 at 13:23

1 Answers1

0

how is it possible for a timer coming from a previous instance to abort a get that belongs to another instance?

Because System.exit(1); operates on the whole application. Once you start that timer it will kill off the whole application after the timeout. Unless it is cancelled.

All the processRequest() instances share the same application so calling System.exit(1); in one of them kills all of them

Vorsprung
  • 32,923
  • 5
  • 39
  • 63
  • I was under the assumption that if the request had already responded it would be impossible to abort() it, and so System.exit(1) would never be executed because an exception would be thrown before it; but in fact get.abort() doesn't have any problem with a closed request. – Bambax Oct 28 '13 at 13:33