Весенний webflux, как управлять последовательным кодом бизнес-логики в реактивном мире - PullRequest
0 голосов
/ 25 сентября 2018

Является ли этот подход дружественным по отношению к реактивным?

У меня есть метод "save" для реактивного контроллера, вызывающий myService.save (request).

Уровень обслуживания должен:

  1. jdbc save (в другом планировщике, поскольку код блокируется),
  2. создание строки шаблона (в другом планировщике),
  3. отправка электронного письма (в другом планировщике),
  4. наконец, верните сохраненную сущность на уровень контроллера

Я не могу объединить все свои вызовы в один конвейер или не знаю, как этого добиться, потому что хочу отправить обратно (1) это потеряно, как только я это сделаю .... flatMap (templateService :: generateStringTemplate), например.

Поэтому вместо этого я запускаю свои подоперации внутри (1).

ЭтоКак я должен справиться с этим или есть умный способ сделать это в одном конвейере?

Ниже код для поддержки вопроса.Спасибо.

Служба вызывается уровнем контроллера

    public Mono<Prospect> save(final Prospect prospect) {

    return Mono.fromCallable(
            () -> {
                Prospect savedProspect = transactionTemplate.execute(status -> prospectRepository.save(prospect));

                templateService.generateProspectSubscription(savedProspect)
                        .map(t ->
                                EmailPostRequest.builder()
                                       ...
                                        .build())
                        .flatMap(emailService::send)
                        .subscribe();

                return savedProspect;
            })
            .subscribeOn(jdbcScheduler);

}

TemplateService

public Mono<String> generateProspectSubscription(final Prospect prospect) {        
    return Mono.fromCallable(
            () -> {
                Map<String, Object> model = new HashMap<>();
               ...

                Template t = freemarkerConfig.getTemplate(WELCOME_EN_FTL);
                String html = FreeMarkerTemplateUtils.processTemplateIntoString(t, model);
                return html;
            }
    ).subscribeOn(freemarkerScheduler);
}

EmailService

 public Mono<Void> send(final EmailPostRequest e) {

    return Mono.fromCallable(
            () -> {
                MimeMessage message = emailSender.createMimeMessage();
                MimeMessageHelper mimeHelper = new MimeMessageHelper(message,
                        MimeMessageHelper.MULTIPART_MODE_MIXED_RELATED,
                        StandardCharsets.UTF_8.name());


                mimeHelper.setTo(e.getTo());
                mimeHelper.setText(e.getText(), true);
                mimeHelper.setSubject(e.getSubject());
                mimeHelper.setFrom(new InternetAddress(e.getFrom(), e.getPersonal()));

                emailSender.send(message);

                return Mono.empty();
            }
    ).subscribeOn(emailScheduler).then();
}

РЕДАКТИРОВАННАЯ СЛУЖБА Я думаю, что эта версия уровня обслуживания чище, но любые комментарии приветствуются

    public Mono<Prospect> save(final Prospect prospect) {

    return Mono.fromCallable(
            () -> transactionTemplate.execute(status -> prospectRepository.save(prospect)))
            .subscribeOn(jdbcScheduler)
            .flatMap(savedProspect -> {
                        templateService.generateProspectSubscription(savedProspect)
                                .map(t ->
                                        EmailPostRequest.builder()
                                                ...
                                                .build())
                                .flatMap(emailService::send)
                                .subscribe();

                        return Mono.just(savedProspect);
                    }
            );
}

1 Ответ

0 голосов
/ 26 сентября 2018

Этот подход нереактивен, так как вы на 100% оборачиваете блокирующие библиотеки.В этом случае вы не сможете увидеть преимущества реактивной среды выполнения, и есть вероятность, что производительность вашего приложения хуже, чем у блокирующей.

Если ваша основная мотивация - производительность, то это, вероятно, противоречит-productive.Разгрузка большого количества работ по блокировке ввода-вывода на специализированную Schedulers требует затрат времени выполнения с точки зрения памяти (создание большего количества потоков) и ЦП (переключение контекста).Если производительность и масштабируемость являются вашей главной задачей, то лучше подойдет переключение на Spring MVC и использование поддержки Flux / Mono там, где она подходит, или даже вызов оператора block().

Если вашОсновной мотивацией является использование конкретной библиотеки, например WebClient Spring Framework с Spring MVC, тогда вам лучше использовать .block() операторы в выбранных местах, а не упаковывать и планировать все.

...