0

I have a BE service A which is sending Rest JSON message to microservice B using Feign client:

@FeignClient(name = "mail-service")
@LoadBalancerClient(name = "mail-service", configuration = LoadBalancerConfiguration.class)
public interface EmailClient {

    @RequestMapping(method = RequestMethod.POST, value = "/engine/emails/register")
    void setUserRegistration(CreateUserDTO createUserDTO);
}

Endpoint:

@RestController
@RequestMapping("/emails")
public class EmailController {

    @RequestMapping(method = RequestMethod.POST, value = "/register", consumes = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<?> register(@Valid @RequestBody CreateUserDTO createUserDTO) {

        emailRestService.processCreateUserMessage(createUserDTO);
        // Implementation of service to send mail to AWS SES
        return new ResponseEntity<>(HttpStatus.OK);
    }
}

Rest Endpoint is sending mail to AWS Ses mail or other mail provider.

The issue is that the fist call from Feign can take 5 seconds and more. I need to make it Async in order FE client not to wait for the mail to be send.

How I can make the Rest call made from Feign Async to there is no wait time for the http response OK to be expected? Is there some better solution to implement this?

Peter Penzov
  • 1,126
  • 134
  • 430
  • 808

1 Answers1

2

AFAIK, Feign does not allow for non-blocking IO, it is a work in progress.

But you can implement your EmailRestService async. Consider the following code (I do no know if processCreateUserMessage is responsible for sending the email as well, but the solution proposed should be extensible to that functionally if necessary):

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

//...

@Service
public class EmailRestServiceImpl implements EmailRestService {
  //...
  
  @Async
  public void processCreateUserMessage(CreateUserDTO createUserDTO) {
    // Implementation of service to send mail to AWS SES
    // ...
  }

}

Please, note the @Async annotation definition.

To enable Spring asynchronous processing, you need to define the @EnableAsync annotation, in your main configuration or in a specific one:

import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;

@Configuration
@EnableAsync
public class AsyncConfiguration {

}

There is no need to change your Controller, although you can return a more convenient HTTP status code if you prefer to:

@RestController
@RequestMapping("/emails")
public class EmailController {

    @RequestMapping(method = RequestMethod.POST, value = "/register", consumes = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<?> register(@Valid @RequestBody CreateUserDTO createUserDTO) {
        // Will be executed asynchronously and return immediately
        emailRestService.processCreateUserMessage(createUserDTO);
        return new ResponseEntity<>(HttpStatus.ACCEPTED);
    }
}
jccampanero
  • 50,989
  • 3
  • 20
  • 49
  • Thanks! In general for microservices which HTTP code is more appropriate OK or ACCEPTED? – Peter Penzov Jun 20 '21 at 14:07
  • You are welcome Peter. It's the same as in the general use case, microservices don't make a difference. You generally use `202 Accepted` when the task hasn't been already performed, but submitted to be performed instead: think in background tasks, background jobs. – jccampanero Jun 20 '21 at 15:04