Pada artikel ini, kita akan melihat cara menggunakan Spring Boot 2.x dan Redis untuk melakukan tugas asinkron, dan kode lengkapnya akan mendemonstrasikan langkah-langkah dalam posting ini.
Sepatu Musim Semi / Musim Semi
Spring adalah framework paling populer untuk mengembangkan aplikasi Java. Dengan demikian, Spring memiliki salah satu komunitas open source terbesar. Selain itu, Spring menyediakan dokumentasi ekstensif dan terkini yang mencakup cara kerja bagian dalam kerangka kerja dan proyek sampel di blognya, dan ada lebih dari 100 ribu pertanyaan dan jawabandi StackOverflow .
Pada awalnya, Spring hanya mendukung konfigurasi berbasis XML dan menjadi sasaran banyak kritik karena hal ini. Kemudian Spring memperkenalkan konfigurasi berbasis anotasi yang mengubah segalanya. Spring 3.0 adalah versi pertama yang mendukung konfigurasi berbasis anotasi. Pada tahun 2014, Spring Boot 1.0 dirilis , benar-benar mengubah cara kita melihat ekosistem framework Spring. Penjelasan lebih rinci tentang sejarah Musim Semi dapat ditemukan di sini .
Redis
Redis adalah salah satu database dalam memori NoSQL yang paling populer. Redis mendukung berbagai jenis struktur data. Redis mendukung berbagai jenis struktur data seperti Set, tabel Hash, Daftar, pasangan nilai kunci sederhana, dan masih banyak lagi. Latensi panggilan Redis kurang dari milidetik, dukungan kumpulan replika, dan sebagainya. Latensi operasi Redis kurang dari milidetik, membuatnya semakin menarik bagi komunitas developer.
Mengapa Eksekusi Tugas Asynchronous
Panggilan API tipikal memiliki lima langkah:
Menjalankan satu atau lebih kueri database (RDBMS / NoSQL)
Satu atau lebih operasi sistem caching (In-Memory, Distributed, dll.)
Beberapa perhitungan (ini mungkin pemrosesan data saat melakukan beberapa operasi matematika)
Memanggil layanan lain (internal / eksternal)
,
. , - 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.
, :
IDE
Gradle
Java
Redis
Spring Boot . Gradle Spring Boot https://start.spring.io/.
:
Spring Data Redis
Spring Web
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
Sekarang kita dapat menjadwalkan tugas menggunakan Rqueue tanpa banyak kode tambahan! Pertimbangan dasar untuk menyiapkan dan menggunakan perpustakaan Rqueue telah disediakan. Satu hal penting yang perlu diingat adalah bahwa terlepas dari apakah tugas tersebut merupakan tugas yang menunggu keputusan atau tidak, defaultnya adalah menganggap bahwa tugas harus diselesaikan sesegera mungkin.
Kode lengkap dari posting ini dapat ditemukan di repositori di GitHub .
Bacaan tambahan
Spring Boot: Membuat Metode Asinkron Menggunakan Anotasi @Async
Eksekusi dan Penjadwalan Tugas Terdistribusi di Java, Didukung oleh Redis