Как обрабатывать асинхронные обратные вызовы синхронно в Java? - PullRequest
0 голосов
/ 08 мая 2018

У меня вопрос, связанный с архитектурой. Это независимый от языка вопрос, но, поскольку я пришел из Java, мне будет легче, если кто-то поведет меня по Java.

По сути, промежуточное программное обеспечение, которое я пишу, связывается со сторонним сервисом на основе SOAP. Вызовы асинхронны - таким образом, что при вызове сервиса он возвращается с ответом 01 - обработка; Это означает, что третье лицо успешно получило запрос. В исходном запросе SOAP каждый раз необходимо отправлять один URL-адрес обратного вызова, когда третье лицо фактически отправляет результат. Таким образом, вызов определенной службы на самом деле не возвращает результат немедленно; результат получен в отдельной конечной точке HTTP в промежуточном программном обеспечении.

Теперь в нашем интерфейсе мы не хотим усложнять взаимодействие с пользователем. Мы хотим, чтобы наши пользователи вызывали функцию промежуточного программного обеспечения (через пункты / кнопки меню) и немедленно получали результат; и оставь грязную работу промежуточному программному обеспечению.

Обратите внимание, что функция промежуточного программного обеспечения (скажем, X ()), которая была вызвана из внешнего интерфейса, и URL-адрес конечной точки промежуточного программного обеспечения (давайте назовем его Y), когда сторонние поставщики отправляют результат, полностью отделены друг от друга. X () каким-то образом должен ждать и затем извлекать результат, захваченный в Y, а затем возвращать результат во внешний интерфейс.

enter image description here

Как мне создать надежное решение для достижения вышеупомянутого поведения? Картина отлично изображает мой случай. Любые предложения будут высоко оценены.

Ответы [ 2 ]

0 голосов
/ 08 мая 2018

Этот вопрос может быть больше о шаблонах интеграции, чем о многопоточности. Но запросы в той же самой прикладной программе / JVM могут быть организованы с использованием комбинации асинхронного вызова и шаблона наблюдателя:

Это лучше сделать на примере (используя ваши знания Java). Проверьте следующие упрощенные компоненты, которые пытаются повторить ваш сценарий:

Сторонний сервис: он предоставляет операцию, которая возвращает идентификатор корреляции и запускает длительное выполнение

class ExternalService {
    public String send() {
        return UUID.randomUUID().toString();
    }
}

Ваш клиентский сервис: Он получает запрос, вызывает сторонний сервис, а затем ждет ответа после регистрации в получателе результатов:

class RequestProcessor {
    public Object submitRequest() {
        String correlationId = new ExternalService().send();

        return new ResultReceiver().register(correlationId).join();
    }
}

Получатель результатов: Предоставляет операцию сторонней службе и поддерживает внутренний реестр корреляций:

class ResultReceiver {

    Map<String, CompletableFuture<Object>> subscribers;

    CompletableFuture<Object> register(String responseId) {
        CompletableFuture<Object> future = new CompletableFuture<Object>();
        this.subscribers.put(responseId, future);

        return future;
    }

    public void externalResponse(String responseId, Object result) {
        this.subscribers.get(responseId).complete(result);
    }
}

В этом случае удобны фьючерсы, обещания, обратные вызовы. Синхронизация выполняется процессором исходного запроса, чтобы принудительно заблокировать выполнение для клиента.

Теперь это может вызвать ряд проблем, которые не рассматриваются в этом упрощенном наборе классов. Некоторые из этих проблем могут быть:

  • состояние гонки между new ExternalService().send() и new ResultReceiver().register(correlationId). Это то, что может быть решено в ResultReceiver, если он понимает, что некоторые ответы могут быть очень быстрыми (двустороннее ожидание, так сказать)
  • Никогда не получающиеся результаты: результаты могут занять слишком много времени или просто столкнуться с ошибками. Эти будущие API обычно предлагают тайм-ауты для принудительного отмены запроса. Например:

    new ResultReceiver().register(correlationId)
        .get(10000, TimeUnit.SECONDS);
    
0 голосов
/ 08 мая 2018

Ну, в чем конкретно проблема?Вы просто создаете API (промежуточное программное обеспечение), которое не возвращает ответ, пока третье лицо не вернет обработанный результат.Внешний интерфейс отправляет запрос в X (), X () обрабатывает этот запрос, отправляя запрос в Y (), а затем продолжает опросить Y (), чтобы увидеть, когда результат готов, затем X () получает результаты из Y () иотправляет его обратно на передний конец.Как фасад.

Существуют некоторые проблемы, связанные с использованием сторонних услуг, которые вы не контролируете, и которые следует учитывать.Прежде всего, вам необходимо реализовать какой-то автоматический выключатель или тайм-аут.Потому что сторонний сервис может зависнуть и никогда не обрабатывать результаты (или обрабатывать их так долго, что нет смысла ждать).Также вам следует подумать о каком-то значимом способе поддержания сайта в рабочем состоянии, даже если сторонняя служба недоступна или обновила их API, или что-то еще мешает вам использовать его.

И только одна последняя мысль в конце.Зачем вам делать то, что уже реализовано, асинхронно синхронно?Это сделано так, вероятно, потому что это может занять время.Блокировка внешнего интерфейса на длительные периоды времени для ожидания результатов делает работу пользователя неприятной, а пользовательский интерфейс не отвечает.Обычно лучше придерживаться асинхронных запросов и показывать пользователям, которых они обрабатывают, но тем временем позволяйте им делать что-то еще.

...