1

I am trying to impose time limit on http end points.

In the example below, I am aiming that this method shall be executed before 5 seconds. If it is taking more time, I would like to throw exception and return error to client.

Spring : 4.1.7
Jersey 1.1.9

Code

import javax.ws.rs.GET;
    import javax.ws.rs.Path;
    import javax.ws.rs.PathParam;
    import javax.ws.rs.Produces;
    import javax.ws.rs.core.Response;


    @Path("/pets")
    @Component
    public class PetsController {


      @GET
      @Produces({MediaTypeApi.JSON, MediaTypeApi.XML})  
      //Timeout of 5 secs
      public List<Pet> getPets() {
       //Return
      }
    }

Any idea to handle this in better way considering optimum utilization of threads.

Abhiram mishra
  • 1,597
  • 2
  • 14
  • 34
Patan
  • 17,073
  • 36
  • 124
  • 198

1 Answers1

0

EDIT

When writing this answer I didn't notice the version of Jersey OP is using. The async API was added in Jersey 2 therefore this answer is not an answer given OP's constraints.

EDIT 2

Apart from upgrading your Jersey libs you might consider migrating your api to Spring MVC and using their async API (available from Spring 3.2). Handling timeouts the Spring way (using the DeferredResult object):

import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;

@RestController
@RequestMapping("/api")
public class AsyncController {

    private static final TIMEOUT = 5000L;

    private final AService aService;

    @Inject
    public AsyncController(final AService aService) {
        this.aService = aService;
    }

    @RequestMapping(value = "/async-endpoint", method = RequestMethod.GET)
    public DeferredResult<ResponseEntity<ADto>> asyncEndpoint() {

        DeferredResult<ResponseEntity<ADto>> deferredResult = new DeferredResult<>(TIMEOUT);

        CompletableFuture
                .supplyAsync(() -> aService.aVeryExpensiveOperation())
                .thenAccept(result -> {
                    deferredResult.setResult(new ResponseEntity<>(result, HttpStatus.OK));
                })
                .exceptionally(throwable -> {
                    deferredResult.setErrorResult(
                            throwable instanceof CompletionException ? throwable.getCause() : throwable);
                    return null;
                });

        return deferredResult;
    }
}

ORIGINAL ANSWER:

There is an example in Jersey Asynchronous Server API Documentation doing exactly what you want:

import javax.ws.rs.container.Suspended;
import javax.ws.rs.container.TimeoutHandler;
import javax.ws.rs.core.Response;
import java.util.concurrent.TimeUnit;

@Path("/resource")
public class AsyncResource {

    @GET
    @Path("/timeoutAsync")
    public void asyncGetWithTimeout(@Suspended final AsyncResponse asyncResponse) {
        asyncResponse.setTimeoutHandler(new TimeoutHandler() {
            @Override
            public void handleTimeout(AsyncResponse asyncResponse) {
                asyncResponse.resume(Response.status(Response.Status.SERVICE_UNAVAILABLE).entity("Operation time out.").build());
            }
        });
        asyncResponse.setTimeout(5, TimeUnit.SECONDS);

        new Thread(new Runnable() {

            @Override
            public void run() {
                String result = veryExpensiveOperation();
                asyncResponse.resume(result);
            }

            private String veryExpensiveOperation() {
                return "Very Expensive Operation with Timeout";
            }
        }).start();
    }
}

Please note that in a real life scenario you'd probably use a threadpool thread instead of creating it yourself like in this Jersey example

jannis
  • 4,843
  • 1
  • 23
  • 53