Search code examples
springspring-bootspring-cloudspring-cloud-feignfeign

Send Async message to microservice


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?


Solution

  • 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);
        }
    }