Java play 2.3.9。从承诺TimeoutException中恢复

时间:2015-05-18 07:04:45

标签: java asynchronous playframework promise

我有一个调用Foursquare API的函数,我想设置一个超时。我想返回一个默认值(如果超时超过,则为空响应)。我的实施:

public Promise<Response> getDetails(final Place place) {
    Logger.debug(BASE_URL + place.getFqId() + "?client_id=" + KEY + "&client_secret=" + SECRET_KEY + "&v=20140806&m=foursquare");

    Promise<Response> response =
    WS.url(BASE_URL + place.getFqId())
    .setQueryParameter("client_id", KEY)
    .setQueryParameter("client_secret", SECRET_KEY)
    .setQueryParameter("v", "20140806")
    .setQueryParameter("m", "foursquare")
    .setTimeout(TIMEOUT)
    .get().map(
      new Function<WSResponse, Response>() {
        public Response apply(WSResponse response) {
          JsonNode json = response.asJson();
          return new FoursquareResponse(place.getFqId(), json);
        }
      }
    );

    response.recover(new Function<Throwable, Response>() {
      public Response apply(Throwable t) throws Throwable {
        Logger.error("error", t);
        Logger.error(place.getFqId());
        return new FoursquareResponse(place.getFqId(), null);
      }
    });

    return response;
  }

我为测试目的设置了一个低超时(1毫秒),并且我仍然收到TimeoutException,即使它进入恢复体(记录错误)。

任何人都可以提供帮助?谢谢。 :)

2 个答案:

答案 0 :(得分:1)

您的response.recover(...)会返回您不使用的Promise<Response>。即您应该重新分配或使用从response.recover(...)返回的承诺。

就像这个例子一样:

Application.java

public class Application extends Controller {

  public static Result timeout() throws Exception {
    int timeout = 2000;
    Thread.sleep(timeout);

    return ok(format("Just give me %d seconds!", timeout / 1000));
  }

  public static Promise<Result> takeSomeTime() throws Exception {

    return couldBeAWhile().map(new F.Function<String, Result>() {

      @Override
      public Result apply(final String body) throws Throwable {
        return ok(body);
      }
    });
  }

  public static Promise<String> couldBeAWhile() {
    Promise<WSResponse> response = WS.url("http://localhost:9000/timeout")
        .setTimeout(1000)
        .get();

  Promise<String> promise = response.map(new F.Function<WSResponse, String>() {

    @Override
    public String apply(final WSResponse wsResponse) throws Throwable {
      return wsResponse.getBody();
    }

  });

  promise = promise.recover(new F.Function<Throwable, String>() {

    public String apply(Throwable t) throws Throwable {
      Logger.error("Error ->", t);
      return "error";
    }
  });

  return promise;
}

routes

GET     /timeout                       controllers.Application.timeout()
GET     /takeSomeTime                  controllers.Application.takeSomeTime()

注意Promise如何重新分配给promise并返回:

  ...

  promise = promise.recover(new F.Function<Throwable, String>() {

    public String apply(Throwable t) throws Throwable {
      Logger.error("Error ->", t);
      return "error";
    }
  });

  return promise;

在上面的示例中,如果您点击http://localhost:9000/takeSomeTime,则会收到“错误”的响应。在触发超时后返回。

因此,在您的情况下,您可能会将您的方法更改为以下内容,它应该按预期工作:

public Promise<Response> getDetails(final Place place) {
    Logger.debug(BASE_URL + place.getFqId() + "?client_id=" + KEY + "&client_secret=" + SECRET_KEY + "&v=20140806&m=foursquare");

    Promise<Response> response =
    WS.url(BASE_URL + place.getFqId())
    .setQueryParameter("client_id", KEY)
    .setQueryParameter("client_secret", SECRET_KEY)
    .setQueryParameter("v", "20140806")
    .setQueryParameter("m", "foursquare")
    .setTimeout(TIMEOUT)
    .get().map(
      new Function<WSResponse, Response>() {
        public Response apply(WSResponse response) {
          JsonNode json = response.asJson();
          return new FoursquareResponse(place.getFqId(), json);
        }
      }
    ).recover(new Function<Throwable, Response>() {
      public Response apply(Throwable t) throws Throwable {
        Logger.error("error", t);
        Logger.error(place.getFqId());
        return new FoursquareResponse(place.getFqId(), null);
      }
    });

    return response;
  }

答案 1 :(得分:0)

我认为问题与您的恢复定义有关。它应该是这样的:

response.recover{
  case ex: Throwable => new Function<Throwable, Response>() {
    public Response apply(Throwable t) throws Throwable {
      Logger.error("error", t);
      Logger.error(place.getFqId());
      return new FoursquareResponse(place.getFqId(), null);
    }
  }
}