Asynchrone Taskausführung mit Redis und Spring Boot

In diesem Artikel wird erläutert, wie Sie mit Spring Boot 2.x und Redis asynchrone Aufgaben ausführen. Der vollständige Code zeigt die Schritte in diesem Beitrag.





Feder / Frühlingsstiefel

Spring  ist das beliebteste Framework für die Entwicklung von Java-Anwendungen. Als solches hat Spring eine der größten Open-Source-Communities. Darüber hinaus bietet Spring in seinem Blog eine umfassende und aktuelle Dokumentation, die das Innenleben des Frameworks und der Beispielprojekte abdeckt. Auf StackOverflow gibt es über  100.000  Fragen und Antworten. 





Anfangs unterstützte Spring nur die XML-basierte Konfiguration und wurde deshalb vielfach kritisiert. Spring führte später eine annotationsbasierte Konfiguration ein, die alles veränderte. Spring 3.0 war die erste Version, die annotationsbasierte Konfiguration unterstützte. Im Jahr 2014 wurde Spring Boot  1.0 veröffentlicht  , was die Sichtweise auf das Spring Framework-Ökosystem grundlegend verändert hat. Eine detailliertere Beschreibung der Frühlingsgeschichte finden Sie  hier





Redis

Redis ist eine der beliebtesten In-Memory-NoSQL-Datenbanken. Redis unterstützt verschiedene Arten von Datenstrukturen. Redis unterstützt verschiedene Arten von Datenstrukturen wie Set, Hash-Tabelle, Liste und einfache Schlüssel-Wert-Paare, um nur einige zu nennen. Die Redis-Anruflatenz beträgt weniger als Millisekunden, die Unterstützung von Replikatsätzen usw. Die Redis-Betriebslatenz beträgt weniger als Millisekunden, was sie für die Entwicklergemeinde noch attraktiver macht.





Warum asynchrone Aufgabenausführung?





Ein typischer API-Aufruf besteht aus fünf Schritten:





  1. Ausführen einer oder mehrerer Datenbankabfragen (RDBMS / NoSQL)





  2. Ein oder mehrere Caching-Systemvorgänge (In-Memory, Distributed usw.)





  3. Einige Berechnungen (dies kann eine Datenverarbeitung sein, während einige mathematische Operationen ausgeführt werden)





  4. Andere Dienste anrufen (intern / extern)





  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





Jetzt können wir Aufgaben mit Rqueue ohne viel Hilfecode planen! Die grundlegenden Überlegungen zum Einrichten und Verwenden der Rqueue-Bibliothek wurden gegeben. Beachten Sie, dass unabhängig davon, ob es sich bei der Aufgabe um eine ausstehende Aufgabe handelt oder nicht, standardmäßig davon ausgegangen wird, dass Aufgaben so schnell wie möglich abgeschlossen werden müssen.





Der vollständige Code dieses Beitrags befindet sich im Repository  auf  GitHub





Zusätzliche Lektüre

Spring Boot: Erstellen asynchroner Methoden mithilfe von @ Async Annotation





Feder und Fäden: Async





Ausführung und Planung verteilter Aufgaben in Java, unterstützt von Redis
























































All Articles