Прерывание, если вызов API для обработчика платежей занимает более 60 секунд - PullRequest
5 голосов
/ 09 апреля 2019

Я интегрируюсь с процессором платежей и пытаюсь разобраться со сценарием, в котором:

  • пользователь нажимает оплату, и на наш сервер делается запрос
  • наш сервер делает запрос обработчику платежей
  • существует значительная задержка на стороне платежного процессора
  • после определенного порога, например 60 секунд, мы предупреждаем пользователя о том, что его платеж был неудачным
  • через 70 секунд обработчик платежа возвращает успешный ответ.

Итак, мне нужно запустить API-вызов для обработчика платежей из HTTP-вызова из пользовательского интерфейса, затем, если это займет более 60 секунд, завершить HTTP-вызов и вернуть пользователю ошибку, а затем, если API-вызов Чтобы обработчик платежей в конце концов преуспел (скажем, через 70 секунд), отправьте электронное письмо команде администраторов.

Я думаю о чем-то вроде этого:

    import javax.ws.rs.client.*;
    import java.util.Timer;
    import java.util.TimerTask;

    ...

    boolean overThreshold = false;
    int timeout = 60; // seconds
    TimerTask task = new TimerTask() {
        @Override
        public void run() {
            overThreshold = true;
            // return a message to user here saying their payment could not be processed
        }
    };

    new Timer(true).schedule(task, timeout * 1000);

    Client client = ClientBuilder.newClient();
    WebTarget webTarget
            = client.target({url of payment processor});
    Invocation.Builder builder = webTarget.request()
            .header(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON);

    final Response response = builder.post(Entity.json(new Gson().toJson(request)));

    if (overThreshold) {
        // send alert email here
    }

Есть несколько проблем, например, run() метод имеет пустое возвращаемое значение, ошибка с overThreshold как доступ из внутреннего класса. Есть ли более элегантный способ сделать это?

1 Ответ

4 голосов
/ 12 апреля 2019

Использование Future.get (timeout) из ExecutorService должно справиться с этим довольно чисто.

Например:

    ExecutorService executor = Executors.newCachedThreadPool();

    // ... set up builder as before ...
    Future<Response> responseFuture = executor.submit(
            () -> builder.post(Entity.json(new Gson().toJson(request))));
    try {
        Response response = responseFuture.get(timeout, TimeUnit.SECONDS);
        // return normal response here
    } catch (TimeoutException ex) {
        executor.submit( () -> {
            Response lateResponse = responseFuture.get();
            // send overThreshold alert email here
            // Dummy return - prefer Callable to Runnable here for exception handling
            return null;
        } );
        // return a message to user here saying their payment could not be processed
    }

Выбор ExecutorService может быть настроен, чтобы соответствовать, или в равной степени быть общим пулом потоков в другом месте приложения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...