Estoy usando la primavera Webflux con JPA datos de primavera usando PostgreSQL como backend db. No quiero bloquear el hilo principal, mientras que la realización de llamadas db como find
y save
. Para lograr el mismo, tengo un programador principal de Controller
clase y una jdbcScheduler
clases de servicio.
La forma en que los he definido es:
@Configuration
@EnableJpaAuditing
public class CommonConfig {
@Value("${spring.datasource.hikari.maximum-pool-size}")
int connectionPoolSize;
@Bean
public Scheduler scheduler() {
return Schedulers.parallel();
}
@Bean
public Scheduler jdbcScheduler() {
return Schedulers.fromExecutor(Executors.newFixedThreadPool(connectionPoolSize));
}
@Bean
public TransactionTemplate transactionTemplate(PlatformTransactionManager transactionManager) {
return new TransactionTemplate(transactionManager);
}
}
Ahora, mientras se hace un leer / llamada en mi capa de servicio que hago:
@Override
public Mono<Config> getConfigByKey(String key) {
return Mono.defer(
() -> Mono.justOrEmpty(configRepository.findByKey(key)))
.subscribeOn(jdbcScheduler)
.publishOn(scheduler);
}
@Override
public Flux<Config> getAllConfigsAfterAppVersion(int appVersion) {
return Flux
.fromIterable(configRepository.findAllByMinAppVersionIsGreaterThanEqual(appVersion))
.subscribeOn(jdbcScheduler)
.publishOn(scheduler);
}
@Override
public Flux<Config> addConfigs(List<Config> configList) {
return Flux.fromIterable(configRepository.saveAll(configList))
.subscribeOn(jdbcScheduler)
.publishOn(scheduler);
}
Y en el controlador, lo hago:
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
Mono<ResponseDto<List<Config>>> addConfigs(@Valid @RequestBody List<Config> configs) {
return configService.addConfigs(configs).collectList()
.map(configList -> new ResponseDto<>(HttpStatus.CREATED.value(), configList, null))
.subscribeOn(scheduler);
}
¿Es esto correcto? y / o si hay una manera mejor manera de hacerlo?
Lo que entiendo por:
.subscribeOn(jdbcScheduler)
.publishOn(scheduler);
es que la tarea se ejecutará en jdbcScheduler
las discusiones y más tarde como resultado será publicado en mi paralelo principal scheduler
. ¿Es correcto este entendimiento?
Su interpretación es correcta con respecto a publishOn
y subscribeOn
( documentación de referencia sede en el proyecto del reactor de esos operadores ).
Si llama el bloqueo de las bibliotecas sin programar que el trabajo de un programador específico, esas llamadas se bloquean uno de los pocos temas disponibles (por defecto, el bucle de eventos Netty) y su aplicación sólo podrán servir a algunas peticiones simultáneamente.
Ahora estoy seguro de lo que estamos tratando de lograr al hacer eso.
En primer lugar, el programador paralelo está diseñado para tareas obligado CPU , que significa que tendrá algunos de ellos, ya que muchos (o un poco más) como núcleos de CPU. En este caso, es como el establecimiento de su tamaño subprocesos al número de núcleos en un contenedor de servlets regular. Su aplicación no será capaz de procesar un gran número de solicitudes simultáneas.
Incluso si usted elige una mejor alternativa (como el Programador elástica), todavía no sea tan bueno como el bucle de eventos Netty, que es donde el procesamiento de solicitudes está programada de forma nativa en la primavera WebFlux.
Si su objetivo final es el rendimiento y la escalabilidad, es envolver el bloqueo de llamadas en una aplicación de reactivos propensos a realizar peor que el contenedor de servlets regular.
En su lugar podría usar Spring MVC y:
- utilizar tipos de retorno de bloqueo habituales cuando se está tratando con una biblioteca de bloqueo, como JPA
- uso
Mono
yFlux
tipos de retorno cuando no está atado a tales bibliotecas
Esto no va a ser sin bloqueo, pero esto será asincrónica todavía y usted será capaz de hacer más trabajo en paralelo, sin atender a la complejidad.