У меня есть два микросервиса, скажем, FrontEnd и BackEnd, для FrontEnd я использую WebFlux и вызываю серверную службу, используя фиктивный клиент, как показано в приведенном ниже примере кода, хотя приведенный ниже пример кода работает, но я хотел иметь общее исключение обработчик, использующий функцию, и передает на onErrorMap
@RestController
@Slf4j
public class MyFrentEndService {
@Autowired
private MyBackEndService client;
@PostMapping(value = "/hello", consumes = "application/json")
public Mono<Void> sayHello(@Valid String msg) {
log.info("Message is {}", msg);
return Mono.create(sink-> {
try {
client.hello(msg);
}catch (FeignException e) {
System.out.println(e.status());
HttpStatus status = e.status() ==0 ? HttpStatus.SERVICE_UNAVAILABLE : HttpStatus.valueOf(e.status());
String message = e.getMessage();
sink.error(new ResponseStatusException(status, message));
}
sink.success();
});
}
}
Пытался использовать onErrorMap, но получил сообщение об ошибке компиляции: используйте Mono вместо Mono<Void>
@RestController
@Slf4j
public class MyFrentEndService {
@Autowired
private MyBackEndService client;
@PostMapping(value = "/hello", consumes = "application/json")
public Mono<Void> sayHello(@Valid String msg) {
log.info("Message is {}", msg);
return Mono.fromSupplier(() -> {
client.hello(msg);
return null;
}).onErrorMap(e->{
HttpStatus status = e.status() ==0 } HttpStatus.SERVICE_UNAVAILABLE : HttpStatus.valueOf(e.status());
String message = e.getMessage();
return new ResponseStatusException(status, message);
});
}
}
Как использовать onErrorMap?




Эта ошибка не связана с оператором onErrorMap. Этот код не компилируется, потому что компилятор не может определить универсальный тип, возвращаемый методом Mono.fromSupplier, как Void — вы возвращаете null для предоставленной функции.
Это следует исправить, выполнив следующие действия:
@PostMapping(value = "/hello", consumes = "application/json")
public Mono<Void> sayHello(@Valid String msg) {
log.info("Message is {}", msg);
return Mono.<Void>fromSupplier(() -> {
client.hello(msg);
return null;
}).onErrorMap(e->{
HttpStatus status = e.status() ==0 ? HttpStatus.SERVICE_UNAVAILABLE : HttpStatus.valueOf(e.status());
String message = e.getMessage();
return new ResponseStatusException(status, message);
});
}
Я думаю, что более идиоматично сделать следующее:
@PostMapping(value = "/hello", consumes = "application/json")
public Mono<Void> sayHello(@Valid String msg) {
log.info("Message is {}", msg);
return Mono.fromRunnable(() -> {
client.hello(msg);
})
.then()
.onErrorMap(e->{
HttpStatus status = e.status() ==0 ? HttpStatus.SERVICE_UNAVAILABLE : HttpStatus.valueOf(e.status());
String message = e.getMessage();
return new ResponseStatusException(status, message);
});
}
Наконец, я бы посоветовал не использовать блокирующие вызовы внутри реактивного конвейера, если вам это действительно не нужно. (предпочитайте WebClient или другой неблокирующий HTTP-клиент, а не блокирующий клиентов как симуляцию).
Реактивное притворство доступно здесь: github.com/Playtika/притворно-реактивный. Но это абстракция только над веб-клиентом. Если этот подход по-прежнему не работает для вас, используйте pubslishOn(Schedulers.boundedElastic()) в цепочке реакторов, чтобы делегировать работу другому потоку. Это не заблокирует поток реактора.
Спасибо за информацию о блокировке вызовов, создание потока не вариант, я буду использовать блокировку ложного вызова клиента, так как у меня есть собственный балансировщик нагрузки с использованием ленты, в надежде на реактивное ложное срабатывание.