I am currently on a Project that builds Microservices, and are trying to move from the more traditional Spring Boot RestClient
to Reactive Stack using Netty and WebClient
as the HTTP Client in order to connect to backend systems.
This is going well for backends with REST APIs, however I'm still having some difficulties implementing WebClient
to services that connect to SOAP backends and Oracle databases, which still uses traditional JDBC.
I managed to find some workaround online regarding JDBC calls that make use of parallel schedulers to publish the result of the blocking JDBC call:
//the method that is called by @Service
@Override
public Mono<TransactionManagerModel> checkTransaction(String transactionId, String channel, String msisdn) {
return asyncCallable(() -> checkTransactionDB(transactionId, channel, msisdn))
.onErrorResume(error -> Mono.error(error));
}
...
//the actual JDBC call
private TransactionManagerModel checkTransactionDB(String transactionId, String channel, String msisdn) {
...
List<TransactionManagerModel> result =
jdbcTemplate.query(CHECK_TRANSACTION, paramMap, new BeanPropertyRowMapper<>(TransactionManagerModel.class));
...
}
//Generic async callable
private <T> Mono<T> asyncCallable(Callable<T> callable) {
return Mono.fromCallable(callable).subscribeOn(Schedulers.parallel()).publishOn(transactionManagerJdbcScheduler);
}
and I think this works quite well.
While for SOAP calls, what I did was encapsulating the SOAP call in a Mono
while the SOAP call itself is using a CloseableHttpClient
which is obviously a blocking HTTP Client.
//The method that is being 'reactive'
public Mono<OfferRs> addOffer(String transactionId, String channel, String serviceId, OfferRq request) {
...
OfferRs result = adapter.addOffer(transactionId, channel, generateRequest(request));
...
}
//The SOAP adapter that uses blocking HTTP Client
public OfferRs addOffer(String transactionId, String channel, JAXBElement<OfferRq> request) {
...
response = (OfferRs) getWebServiceTemplate().marshalSendAndReceive(url, request, webServiceMessage -> {
try {
SoapHeader soapHeader = ((SoapMessage) webServiceMessage).getSoapHeader();
ObjectFactory headerFactory = new ObjectFactory();
AuthenticationHeader authHeader = headerFactory.createAuthenticationHeader();
authHeader.setUserName(username);
authHeader.setPassWord(password);
JAXBContext headerContext = JAXBContext.newInstance(AuthenticationHeader.class);
Marshaller marshaller = headerContext.createMarshaller();
marshaller.marshal(authHeader, soapHeader.getResult());
} catch (Exception ex) {
log.error("Failed to marshall SOAP Header!", ex);
}
});
return response;
...
}
My question is: Does this implementation for SOAP calls "reactive" enough that I won't have to worry about some calls being blocked in some part of the microservice? I have already implemented reactive stack - calling a block()
explicitly will throw an exception as it's not permitted if using Netty.
Or should I adapt the use of parallel Schedulers
in SOAP calls as well?
Schedulers.parallel()
will create workers on multiple cores, which is probably not needed due to the fact that there is a setup time and using multiple cores is usually only needed if there is cpu intensive work. The second thing is the use ofpublishOn
. – PachstonpublishOn
statement the current thread will switch from the designated thread on the designated core to a thread in thetransactionManagerJdbcScheduler
(i dont know what type ofScheduler
this is. I'd probably just start out with a singleSchedulers.boundedElastic()
placed ononSubscribe
as this scheduler will scale up and down as needed and after 60s remove unused threads. It has a cap of cpu cores x 10 threads. – PachstontransactionManagerJdbcScheduler
was this implementation:Schedulers.fromExecutor(Executors.newFixedThreadPool(connectionPoolSize));
whereconnectionPoolSize
is the amount of max conn pool the JDBC is set (with Hikari); which after some thought, might be an overkill due to the amount of threads it will create. I'm thinking about usingboundedElastic()
orExecutors.newCachedThreadPool()
instead. – BullfrogSchedulers
for Publish and Subscribe affect the performance due to context switching? – Bullfrog