简体   繁体   中英

@Async API endpoint Spring Webflux

I have a requirement to write Spring Webflux endpoint ( Router function ) to send out mail to list of the mail recipients. UI will select the list of mail recipients and sends out the list to the API that I will be writing. Im looking to imlement the endpoint in such a way as soon I receive the request, I should send out the response to the UI saying the Emails are being sent. After sending the response, I should continue the mail sending work asynchronously. I can't use @async annotation like we use in Spring MVC as it an anti pattern in the reactive world.

Since Im using spring webflux to develop API, how can i send the repsonse.

I have a below strucuture in my code.

Router.java

@Bean
public RouterFunction<ServerResponse> sendEmail() {
 return route(POST("/email").and(accept(APPLICATION_JSON)), handler::sendEmail);
}

Handler.java

@Autowired
EmailService emailService;

public Mono<ServerResponse> sendEmail(ServerRequest request) {
    Mono<PojoA> pojoAMono = request.bodyToMono(PojoA.class);
    return pojoAMono.flatMap(pojoA -> {
       return emailService.sendEmail(pojoA).flatMap(mailSent -> {
         return  ServerResponse
        .status(HttpStatus.OK)
        .contentType(MediaType.APPLICATION_JSON)
        .body("Mails are being sent", String.class));
       });
    });
    
}

You could just directly return the response to the caller and after that stream completes run the email sending as a side effect. This can be done with doFinally that is executed after the stream completes.

So your code could look like this:

public Mono<ServerResponse> sendEmail(ServerRequest request) {
    return request.bodyToMono(PojoA.class)
            .map(this::sendEmailSideEffect)
            .flatMap(pojoA -> ServerResponse
                    .status(HttpStatus.OK)
                    .contentType(MediaType.APPLICATION_JSON)
                    .body("Mails are being sent", String.class));
}

private Mono<PojoA> sendEmailSideEffect(PojoA pojoA) {
    return Mono.just(pojoA)
            .doFinally(signalType -> emailService.sendEmails(pojoA));
}

You should build the response and then process the data (send email).

Something like this:

@Bean
public RouterFunction<ServerResponse> sendEmail() {
    return route(POST("/test").and(accept(APPLICATION_JSON)), this::someMethod);
}

Mono<ServerResponse> someMethod(ServerRequest serverRequest) {
    return ServerResponse.ok().build()
            .doOnNext(r -> Mono.just("data") //doing some process like send email
                    .delayElement(Duration.ofSeconds(2))
                    .subscribeOn(Schedulers.parallel())
                    .log()
                    .subscribe());
}

For testing purpose, I put a delay to you see the data processing after response sent.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM