Uploaded image for project: 'CXF'
  1. CXF
  2. CXF-6395

Call setTimeout() in a second request cause illegalStateException from web container.

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Major
    • Resolution: Fixed
    • None
    • 3.1.1, 3.0.6
    • JAX-RS
    • None
    • Advanced

    Description

      Come from a TCK test case:
      Resource class has two methods:
      static AsyncResponse asyncResponse;
      @GET
      @Path("/suspend")
      public void getSuspendResponse(@Suspended AsyncResponse async)

      { asyncResponse = async; }

      @GET
      @Path("/setTimeOut")
      public String setTimeOut()

      { boolean setTimeout = asyncResponse.setTimeout(10, TimeUnit.SECONDS); return String.valueOf(setTimeout) }

      The first request invokes method getSuspendResponse(), the AsyncResponse is in suspend status. The second request invokes method setTimeOut() to invoke setTimeOut() method of the suspend AsyncRespone. AsyncResponseImp.setTimeout() -> cont.suspend(timeout)(Servlet3ContinuationProvider$Servlet3Continuation) -> context.setTimeout(timeout);
      The the impl class of AsyncContext throw a illegalStateException: called setTimeout after the container-initiated dispatch which called startAsync has returned.
      According to the javadoc of AsyncContext class, seemed the behavior of AsyncContext is correct. We tried to challenge this test case, but was rejected.

      Checked restesay code, found they thought the invocation is illegal, but they provide a work around:

      protected WeakReference<Thread> creatingThread = new WeakReference<Thread>(Thread.currentThread());
      protected ScheduledFuture timeoutFuture; // this is to get around TCK tests that call setTimeout in a separate thread which is illegal.
      protected ScheduledExecutorService asyncScheduler;

      public synchronized boolean setTimeout(long time, TimeUnit unit) throws IllegalStateException {
      ......
      Thread thread = creatingThread.get();
      if (thread != null && thread != Thread.currentThread()) {
      // this is to get around TCK tests that call setTimeout in a separate thread which is illegal.
      if (timeoutFuture != null && !timeoutFuture.cancel(false))

      { return false; }

      Runnable task = new Runnable() {
      @Override
      public void run()

      { handleTimeout(); }

      };
      timeoutFuture = asyncScheduler.schedule(task, time, unit);
      return true;
      } else

      { ...... }

      }

      Check if current thread is the creating thread of AsyncResponseImpl object, if not, means setTimeout() method is called in a second request, then handle the timeout with a ScheduledExecutorService instead of AsyncContext to avoid the illegalState exception.

      I tried to add above code to setTimeout() method. It's ok when setTimeout() was called, and handleTimeout() method was called also when timeout. But client can't get a response which said timeout until connection timeout.

      Attachments

        Activity

          People

            sergey_beryozkin Sergey Beryozkin
            weiz Wei Zheng
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: