در RabbitMQ، وقتی یک پیام در یک صف به عنوان یک نامه مرده به اصطلاح (یک پیامی که مصرف‌کنندگان نمی‌توانند پردازش کنند) فرستاده می‌شود، به یک تبادل دیگر مسیر یابی می‌شود که آن را تبادل نامه مرده (dead letter exchange) می‌نامیم. تبادل نامه مرده سپس نامه مرده را به یک صف ارسال می‌کند که آن را صف نامه مرده (dead letter queue) می‌نامیم.

توضیح نامه مرده - صف

صف نامه مرده

تصویر بالا فرایند کامل از تولید نامه‌های مرده تا پردازش آن‌ها را توضیح می‌دهد.

تولید نامه‌های مرده

شرایط زیر برای تولید نامه‌های مرده هستند:

  • پیام به صورت دستی توسط مصرف‌کننده رد می‌شود (basic.reject / basic.nack) و requeue = false.
  • زمان تا زنده ماندن پیام (TTL) منقضی می‌شود.
  • صف حداکثر طول را کسب می‌کند.

گام‌های پردازش صف نامه مرده

  1. تعریف یک تبادل نامه مرده (به نامش فریب نخورید، این فقط یک تبادل معمولی است و فقط در زمینه پردازش نامه مرده به این نام گفته می‌شود).
  2. تعریف یک صف برای بستن به تبادل نامه مرده (این صف صف نامه مرده است و همچنین یک صف معمولی است).
  3. تعریف یک مصرف‌کننده نامه مرده برای مصرف کردن صف نامه مرده (از نامش فریب نخورید، این همچنین یک مصرف‌کننده معمولی است).
  4. بستن تبادل نامه مرده به صف مشخص (صفی که باید نامه‌های مرده را پردازش کند باید بسته شود).

نکته: برای اصل موضوع به تصویر بالا مراجعه کنید. تمام زبان‌های برنامه‌نویسی به یک شکل مشابه با صف‌های نامه مرده رخ می‌دهند.

پردازش صف نامه مرده در Golang

1. تعریف تبادل نامه مرده

مانند یک تبادل معمولی تعریف کنید.

// تعریف تبادل
err = ch.ExchangeDeclare(
    "tizi365.dead",   // نام تبادل
    "topic", // نوع تبادل
    true,     // پایدار
    false,
    false,
    false,
    nil,
)

2. تعریف صف نامه مرده

مانند یک صف معمولی تعریف کنید.

    // تعریف صف
    q, err := ch.QueueDeclare(
        "",    // نام صف، برای تولید یک صف تصادفی رها شود
        false, // صف پایدار
        false,
        true,
        false,
        nil,
    )

    // بستن صف به تبادل نامه مرده
    err = ch.QueueBind(
        q.Name, // نام صف
        "#",     // کلید مسیری، # به معنای تطبیق همه‌ی کلیدهای مسیری است و به معنای دریافت همه‌ی پیام‌های نامه مرده است
        "tizi365.dead", // نام تبادل نامه مرده
        false,
        nil)

نکته: صف نامه مرده را مانند یک صف معمولی در نظر بگیرید.

3. تعریف مصرف‌کننده نامه مرده

// ایجاد یک مصرف‌کننده
msgs, err := ch.Consume(
    q.Name, // ارجاع به نام صف نامه مرده قبلی
    "",     // نام مصرف‌کننده، اگر فراهم نشود، یک نام تصادفی تولید خواهد شد
    true,   // تأیید خودکار پردازش پیام
    false, 
    false, 
    false, 
    nil,
)

// حلقه برای مصرف کردن پیام‌ها از صف نامه مرده
for d := range msgs {
    log.Printf("پیام نامه مرده دریافت شد: %s", d.Body)
}

4. بستن تبادل نامه مرده به یک صف خاص

	// ویژگی‌های صف
	props := make(map[string]interface{})
	// بستن تبادل نامه مرده
	props["x-dead-letter-exchange"] = "tizi365.dead"
	// اختیاری: تنظیم کلید مسیری زمانی که نامه مرده به تبادل نامه مرده ارسال می‌شود. اگر تنظیم نشود، کلید مسیری اصلی پیام استفاده خواهد شد.
	// props["x-dead-letter-routing-key"] = "www.tizi365.com"

	q, err := ch.QueueDeclare(
		"tizi365.demo.hello", // نام صف
		true,   // پایدار
		false, 
		false, 
		false,   
		props,     // تنظیم ویژگی‌های صف
	)

به این ترتیب، اگر پیام‌های موجود در صف tizi365.demo.hello نامه‌های مرده شوند، آن‌ها به تبادل نامه مرده tizi365.dead فرستاده می‌شوند.