Ejecución de tareas asincrónicas mediante Redis y Spring Boot

En este artículo, veremos cómo usar Spring Boot 2.xy Redis para realizar tareas asincrónicas, y el código completo demostrará los pasos en esta publicación.





Primavera / arranque de primavera

Spring  es el marco más popular para desarrollar aplicaciones Java. Como tal, Spring tiene una de las comunidades de código abierto más grandes. Además, Spring proporciona documentación extensa y actualizada que cubre el funcionamiento interno del marco y proyectos de muestra en su blog, y hay más de 100k  preguntas y respuestasen  StackOverflow





Al principio, Spring solo admitía la configuración basada en XML y fue objeto de muchas críticas debido a esto. Más tarde, Spring introdujo una configuración basada en anotaciones que cambió todo. Spring 3.0 fue la primera versión que admitió la configuración basada en anotaciones. Spring Boot  1.0 se lanzó en 2014  , cambiando por completo la forma en que vemos el ecosistema del marco de Spring. Puede encontrar una descripción más detallada de la historia de Spring  aquí





Redis

Redis es una de las bases de datos en memoria NoSQL más populares. Redis admite diferentes tipos de estructuras de datos. Redis admite varios tipos de estructuras de datos como Set, Hash table, List, pares simples de clave-valor por nombrar solo algunos. La latencia de llamadas de Redis es inferior a milisegundos, la compatibilidad con conjuntos de réplicas, etc. La latencia de la operación de Redis es inferior a milisegundos, lo que lo hace aún más atractivo para la comunidad de desarrolladores.





Por qué la ejecución de tareas asincrónicas





Una llamada a la API típica tiene cinco pasos:





  1. Ejecutar una o más consultas de base de datos (RDBMS / NoSQL)





  2. Una o más operaciones del sistema de almacenamiento en caché (en memoria, distribuidas, etc.)





  3. Algunos cálculos (esto puede ser el procesamiento de datos mientras se realizan algunas operaciones matemáticas)





  4. Llamar a otros servicios (internos / externos)





  5. ,    





. , - 7 .  , . 





, , API. , 1K , API, API .  API, , . 





, , cron, .  , , crontab UNIX, Chronos, Spring,    Scheduled ❤️. 





cron , , , , .    , , /.    ,  .  , .  , - , - .  , , /.  —  , .    , .  / , , SQS, , 15 , , ​​ 7 7 . .





Rqueue

Rqueue — ,  Spring,  Redis . Rqueue Redis, Redis , Kafka, SQS.  - Redis .   8,4% - Redis.





, Kafka/SQS, , , , , Rqueue Redis.





, Kafka, , , , Redis, , / Redis Rqueue. Rqueue





Rqueue , .    Rqueue.





, :





  1. IDE





  2. Gradle 





  3. Java





  4. Redis 





 Spring Boot .  Gradle Spring Boot  https://start.spring.io/.





:  





  1. Spring Data Redis





  2. Spring Web





  3. Lombok





/ :





  Rqueue  . Rqueue — Spring , , Spring Redis.





spring boot starter  Rqueue com.github.sonus21:rqueue-spring-boot-starter:2.0.0-RELEASE :





dependencies {  
  implementation 'org.springframework.boot:spring-boot-starter-data-redis'
  implementation 'org.springframework.boot:spring-boot-starter-web'
  implementation 'com.github.sonus21:rqueue-spring-boot-starter:2.0.0-RELEASE'
  compileOnly 'org.projectlombok:lombok'   
  annotationProcessor 'org.projectlombok:lombok'
  providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
  testImplementation('org.springframework.boot:spring-boot-starter-test') {
    exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'  
  }
}
      
      







Redis Spring Boot.  WEB MVC.





application :





@SpringBootApplication
@EnableRedisRepositories
@EnableWebMvc
public class AsynchronousTaskExecutorApplication { 
  public static void main(String[] args) { 
    SpringApplication.run(AsynchronousTaskExecutorApplication.class, args);
  }
}
      
      







Rqueue .   RqueueListener



.  RqueuListener



, .  deadLetterQueue



.  .  , ,  . numRetries







Java  MessageListener



:





@Component
@Slf4j
public class MessageListener {

  @RqueueListener(value = "${email.queue.name}") (1)
  public void sendEmail(Email email) {
    log.info("Email {}", email);
  }

  @RqueueListener(value = "${invoice.queue.name}") (2)
  public void generateInvoice(Invoice invoice) {
    log.info("Invoice {}", invoice);
  }
}
      
      



Email



Invoice



- .  .





Invoice.java:





import lombok.Data;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Invoice {
  private String id;
  private String type;
}
      
      







Email.java:





import lombok.Data;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Email {
  private String email;
  private String subject;
  private String content;
}
      
      



  RqueueMessageSender



 bean-. , .  enqueue, enqueueIn.





 RqueueMessageSender



bean-.





  . 





-, 30 .  30000 () .  , , .  GET, sendEmail



  generateInvoice



, POST. 





@RestController
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@Slf4j
public class Controller {
  private @NonNull RqueueMessageSender rqueueMessageSender;

  @Value("${email.queue.name}")
  private String emailQueueName;

  @Value("${invoice.queue.name}")
  private String invoiceQueueName;

  @Value("${invoice.queue.delay}")
  private Long invoiceDelay;

  @GetMapping("email")
  public String sendEmail(
      @RequestParam String email, @RequestParam String subject, @RequestParam String content) {
    log.info("Sending email");
    rqueueMessageSender.enqueu(emailQueueName, new Email(email, subject, content));
    return "Please check your inbox!";
  }

  @GetMapping("invoice")
  public String generateInvoice(@RequestParam String id, @RequestParam String type) {
    log.info("Generate invoice");
    rqueueMessageSender.enqueueIn(invoiceQueueName, new Invoice(id, type), invoiceDelay);
    return "Invoice would be generated in " + invoiceDelay + " milliseconds";
  }
}
      
      



application.properties :





email.queue.name=email-queue
invoice.queue.name=invoice-queue
# 30 seconds delay for invoice
invoice.queue.delay=300000
      
      



.   .





, :





30 :





http://localhost:8080/invoice?id=INV-1234&type=PROFORMA





¡Ahora podemos programar tareas usando Rqueue sin mucho código adicional! Se han proporcionado las consideraciones básicas para configurar y usar la biblioteca Rqueue. Una cosa importante a tener en cuenta es que si la tarea es una tarea pendiente o no, lo predeterminado es asumir que las tareas deben completarse lo antes posible.





El código completo de esta publicación se puede encontrar en el repositorio  de  GitHub





Lectura adicional

Spring Boot: Creación de métodos asincrónicos mediante la anotación @Async





Primavera e hilos: Async





Ejecución y programación de tareas distribuidas en Java, con tecnología de Redis
























































All Articles