Acknowledge Consumer & Antrean Ulang
Kuasai acknowledge consumer dan pelajari cara mengantrekan ulang pesan saat pemrosesan gagal. Rancang consumer toleran terhadap kegagalan yang dapat menangani kesalahan dengan baik.
Acknowledge Consumer & Antrean Ulang adalah pelajaran RabbitMQ Messaging & Async Systems gratis di CoddyKit. Ini adalah pelajaran 3 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar RabbitMQ Messaging & Async Systems, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus RabbitMQ Messaging & Async Systems mencakup 4 pelajaran total.
Bagian dari pelajaran ini belum diterjemahkan dan ditampilkan dalam bahasa Inggris.
Reliable Message Consumption
In distributed systems, ensuring messages are processed correctly is vital. What happens if a consumer crashes mid-processing? Or if a message causes an error?
This lesson explores consumer acknowledgements and requeuing, essential techniques for building fault-tolerant message consumers.
ACKs: The Handshake
A consumer acknowledgement (ACK) is a signal sent by the consumer back to RabbitMQ. It tells the broker: "I've successfully received and processed this message."
- Without an ACK, RabbitMQ assumes the message hasn't been processed.
- This mechanism prevents message loss if a consumer fails before finishing its work.
Automatic vs. Manual ACKs
RabbitMQ offers two ways to acknowledge messages:
- Automatic (
autoAck=true): Messages are acknowledged immediately upon delivery to the consumer. Simple, but risky if processing fails. - Manual (
autoAck=false): The consumer explicitly sends an ACK after successful processing. This is the default and recommended for reliable systems.
We'll focus on manual acknowledgements for robustness.
Sending a Message (Producer)
Let's set up a simple Java producer to send a message. This message will be consumed later, and we'll apply manual acknowledgements.
Run this code to send a "Hello RabbitMQ!" message.
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.nio.charset.StandardCharsets;
public class MyProducer {
private final static String QUEUE_NAME = "ack_queue";
public static void main(String[] argv) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost"); // Connect to local RabbitMQ
try (Connection connection = factory.newConnection();
Channel channel = connection.createChannel()) {
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
String message = "Hello RabbitMQ!";
channel.basicPublish("", QUEUE_NAME, null, message.getBytes(StandardCharsets.UTF_8));
System.out.println(" [x] Sent '" + message + "'");
}
}
}Manual Acknowledgements in Action
Now, let's create a consumer that uses manual acknowledgements. Notice the autoAck parameter is set to false when consuming.
The channel.basicAck() call confirms successful processing.
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DeliverCallback;
import java.nio.charset.StandardCharsets;
public class MyConsumerAck {
private final static String QUEUE_NAME = "ack_queue";
public static void main(String[] argv) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody(), StandardCharsets.UTF_8);
System.out.println(" [x] Received '" + message + "'");
try {
// Simulate processing work
Thread.sleep(1000);
System.out.println(" [x] Done processing '" + message + "'");
channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false); // Manual ACK!
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println(" [!] Processing interrupted.");
// In a real app, you might re-queue or handle error
}
};
// autoAck is set to false for manual acknowledgements
channel.basicConsume(QUEUE_NAME, false, deliverCallback, consumerTag -> {});
}
}When Processing Fails
What if our consumer encounters an error during message processing? If we only use basicAck, the message is lost even if processing wasn't completed.
RabbitMQ provides ways to inform the broker that a message could not be processed successfully, giving us options to handle it.
Requeuing Failed Messages
If a message fails processing due to a transient error (e.g., database connection down), you might want to retry it later. Use channel.basicNack(deliveryTag, multiple, requeue) or channel.basicReject(deliveryTag, requeue).
- Setting
requeuetotruesends the message back to the queue for another consumer to pick up.
Run this consumer. It will intentionally fail twice and then successfully process the message.
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DeliverCallback;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;
public class MyConsumerRequeue {
private final static String QUEUE_NAME = "ack_queue";
private static int attemptCount = 0;
public static void main(String[] argv) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody(), StandardCharsets.UTF_8);
long deliveryTag = delivery.getEnvelope().getDeliveryTag();
System.out.println(" [x] Received '" + message + "' (Attempt: " + (++attemptCount) + ")");
try {
if (attemptCount <= 2) { // Simulate failure for first 2 attempts
throw new RuntimeException("Simulated processing error!");
}
// Simulate successful processing
Thread.sleep(1000);
System.out.println(" [x] Successfully processed '" + message + "'");
channel.basicAck(deliveryTag, false); // ACK on success
} catch (Exception e) {
System.err.println(" [!] Error processing '" + message + "': " + e.getMessage());
channel.basicNack(deliveryTag, false, true); // NACK and requeue!
System.out.println(" [!] Message '" + message + "' requeued.");
}
};
channel.basicConsume(QUEUE_NAME, false, deliverCallback, consumerTag -> {});
}
}Discarding Problematic Messages
Sometimes, a message is fundamentally flawed and will *always* cause an error. Requeuing it repeatedly is pointless and can lead to a "poison message" loop.
In such cases, set requeue to false. This discards the message from the queue. Often, these messages are sent to a Dead Letter Exchange (DLX) for later inspection, but we'll cover DLX in a future lesson.
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DeliverCallback;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;
public class MyConsumerReject {
private final static String QUEUE_NAME = "ack_queue";
public static void main(String[] argv) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody(), StandardCharsets.UTF_8);
long deliveryTag = delivery.getEnvelope().getDeliveryTag();
System.out.println(" [x] Received '" + message + "'");
// Simulate an unrecoverable error
System.err.println(" [!] Fatal error for '" + message + "'. Discarding.");
channel.basicNack(deliveryTag, false, false); // NACK and DO NOT requeue!
System.out.println(" [!] Message '" + message + "' rejected (not requeued).");
};
channel.basicConsume(QUEUE_NAME, false, deliverCallback, consumerTag -> {});
}
}Idempotent Consumers
When you requeue messages, there's a chance a consumer might process the same message multiple times.
It's crucial to design your consumers to be idempotent. This means processing the same message twice (or more) produces the same result as processing it once, without unintended side effects.
Reliability Check
Consider a RabbitMQ consumer configured with manual acknowledgements. If a message is received but the consumer crashes *before* calling channel.basicAck() or channel.basicNack(), what typically happens to that message?
Recap: Building Reliable Consumers
You've learned how to make your RabbitMQ consumers resilient:
- Manual Acknowledgements: Give consumers control over message fate.
- Requeuing: Retry messages for transient failures using
basicNack(..., true). - Discarding: Prevent poison message loops with
basicNack(..., false). - Idempotency: Design consumers to handle duplicate deliveries gracefully.
These techniques are fundamental for building robust, fault-tolerant messaging systems.
Pertanyaan yang Sering Diajukan
Apakah pelajaran “Acknowledge Consumer & Antrean Ulang” gratis?
Ya — teks lengkap “Acknowledge Consumer & Antrean Ulang” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus RabbitMQ Messaging & Async Systems, upgrade ke CoddyKit PRO. Kursus RabbitMQ Messaging & Async Systems mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “Acknowledge Consumer & Antrean Ulang”?
Kuasai acknowledge consumer dan pelajari cara mengantrekan ulang pesan saat pemrosesan gagal. Rancang consumer toleran terhadap kegagalan yang dapat menangani kesalahan dengan baik. Kamu berlatih RabbitMQ Messaging & Async Systems dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai RabbitMQ Messaging & Async Systems?
Tidak diperlukan pengalaman sebelumnya. RabbitMQ Messaging & Async Systems di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 3 dari 4.
Berapa lama pelajaran “Acknowledge Consumer & Antrean Ulang” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran RabbitMQ Messaging & Async Systems ini?
Ya. Setiap pelajaran RabbitMQ Messaging & Async Systems menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.
Semua pelajaran dalam kursus ini
- Pesan dan Antrean Persisten
- Konfirmasi Publisher untuk Keandalan
- Acknowledge Consumer & Antrean Ulang
- Transaksi vs Konfirmasi Penerbit