Этот вопрос может быть больше о шаблонах интеграции, чем о многопоточности. Но запросы в той же самой прикладной программе / 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);