laravel-micro-rabbitmq maintained by azizdevfull
🐉 Laravel MicroRabbit
MicroRabbit — bu Laravel mikroxizmatlari (Microservices) uchun yaratilgan, "Enterprise" darajasidagi o'zini-o'zi tiklovchi (Self-Healing) RabbitMQ event-bus kutubxonasi.
U shunchaki xabarlarni jo'natib qabul qilmaydi. U tarmoq uzilishlari, server qulashlari, dublikat xabarlar, zaharli ma'lumotlar (poison payloads) va qotib qolgan jarayonlar ta'sirini keskin kamaytirish uchun mo'ljallangan qudratli yadroga ega.
📑 Mundarija
- 🐉 Laravel MicroRabbit
- 📑 Mundarija
- 📦 1. O'rnatish
- ⚙️ 2. Konfiguratsiya (
config/micro-rabbitmq.php) - 🎧 3. Xabarlarni Qabul Qilish (Consumer)
- 📨 4. Xabar Jo'natish (Publish)
- ⏱ 5. RPC - Sinxron Javob Kutish
- ⚡ 6. Circuit Breaker - Domino Qulashini To'xtatish
- 🛡 7. Transactional Outbox Pattern
- 🧱 8. Chidamlilik va Himoya (Fault Tolerance)
- 🧪 9. Test Yozish (Faking)
- 💻 10. Konsol Komandalari
📦 1. O'rnatish
Kutubxonani Composer orqali loyihangizga qo'shing:
composer require azizdevfull/laravel-micro-rabbitmq
So'ngra kutubxona sozlamalari (config) va Outbox tizimi uchun migratsiyalarni loyihangizga ko'chirib oling:
php artisan vendor:publish --tag="micro-rabbitmq-config"
php artisan vendor:publish --tag="micro-rabbit-migrations"
Baza jadvallarini yarating:
php artisan migrate
.env faylingizga RabbitMQ ulanish ma'lumotlarini kiriting:
MICRO_RABBITMQ_HOST=127.0.0.1
MICRO_RABBITMQ_PORT=5672
MICRO_RABBITMQ_USER=guest
MICRO_RABBITMQ_PASSWORD=guest
# Majburiy emas, qo'shimcha xavfsizlik sozlamalari:
MICRO_RABBITMQ_HEARTBEAT=30
MICRO_RABBITMQ_OUTBOX=false
MICRO_RABBITMQ_MONITORING=true
MICRO_RABBITMQ_PUBLISH_TIMEOUT=5
MICRO_RABBITMQ_OUTBOX_BATCH_SIZE=20
idempotency va distributed lock funksiyalari uchun production'da CACHE_DRIVER=redis tavsiya qilinadi.
⚙️ 2. Konfiguratsiya (config/micro-rabbitmq.php)
Kutubxonani publish qilganingizdan so'ng, loyihangizda config/micro-rabbitmq.php fayli paydo bo'ladi. Uning ichidagi asosiy sozlamalar nima vazifa bajarishini bilish juda muhim:
connection.heartbeat: (Default: 30). Tarmoq xavfsizlik devorlari (Firewall) jim turgan ulanishni uzib yubormasligi uchun Worker har 30 soniyada RabbitMQ ga "Men tirikman" deb belgi (ping) berib turadi. Bu o'lik ulanishlarning oldini oladi.features.idempotency: Dublikatlardan himoya. Yoqilgan bo'lsa, tizimmessage_idlarni keshda saqlaydi va bitta xatni 2 marta o'qimaydi.features.idempotency_ttl_seconds: Idempotency kaliti cache'da qancha vaqt yashashi (Default:86400soniya).features.idempotency_processing_ttl_seconds: Worker ishlayotgan paytdagi lock qancha yashashi (Default:300soniya).features.publish_timeout_seconds: Oddiypublish()broker tasdig'ini maksimal necha soniya kutishi (Default:5).consumer.prefetch_count/MICRO_RABBITMQ_PREFETCH: Har bir consumer bir vaqtda nechta unacked xabar ushlashini belgilaydi. Throughputni oshiradi, lekin juda katta qiymat fairness va xotira sarfiga salbiy ta'sir qilishi mumkin.features.publish_confirm_batch_size/MICRO_RABBITMQ_PUBLISH_CONFIRM_BATCH: Publisher broker confirm'ni har nechta xabardan keyin kutishini belgilaydi. Katta batch odatda publish tezligini oshiradi.features.publish_confirm_max_wait_ms/MICRO_RABBITMQ_PUBLISH_CONFIRM_MAX_WAIT_MS: Batch to'lmagan bo'lsa ham necha ms dan keyin confirm flush bo'lishi. Kichik qiymat latency'ni tushiradi, katta qiymat throughput'ni oshirishi mumkin.features.tracing: Yoqilgan bo'lsa, kelgantrace_id(yoki yangi UUID)ContextvaLog::withContext()orqali barcha log yozuvlariga avtomatik qo'shiladi. Handler ichida alohida hech narsa qilmasdan ELK/Loki da so'rovni oxirigacha kuzatish mumkin bo'ladi.features.outbox.enabled: Transactional Outbox pattern'ni yoqadi. Xatlar to'g'ridan-to'g'ri havo orqali emas, Baza orqali kafolatli jo'natiladi.features.outbox.max_attempts: RabbitMQ o'chib qolsa, Outbox worker xatni jo'natishga necha marta urinishini belgilaydi (Default: 3).features.outbox.publish_timeout_seconds: Outbox relay broker tasdig'ini maksimal necha soniya kutishi (Default:5).features.outbox.batch_size: Outbox worker bir aylanishda nechta xabar olishga urinishini belgilaydi (Default:20).paths:micro:cacheqaysi papkalarni skan qilishini belgilaydi. Default:[base_path('app')].retry.backoff_multiplier,retry.max_delay_ms,retry.jitter_ms: Retry kechikishining exponential backoff+jitter strategiyasi.retry.non_retryable_exceptions: Qayta urinilmaydigan exception klasslari ro'yxati.circuit_breaker.enabled/MICRO_RABBITMQ_CIRCUIT_BREAKER: RPC uchun Circuit Breaker'ni yoqadi/o'chiradi (Default:true).circuit_breaker.threshold/MICRO_RABBITMQ_CB_THRESHOLD: Nechta ketma-ket xatoda circuit ochiladi (Default:5).circuit_breaker.timeout_seconds/MICRO_RABBITMQ_CB_TIMEOUT: Circuit ochiq turgan vaqt (soniyada). Bu vaqtdan keyin bitta "probe" request o'tkaziladi (Default:30).monitoring.*: Metrika cache'i va alert thresholdlari (outbox backlog,blocked,DLQ size,publish timeout) uchun sozlamalar.
Production benchmarklar uchun amaliy boshlang'ich tuning:
MICRO_RABBITMQ_PREFETCH=20
MICRO_RABBITMQ_PUBLISH_CONFIRM_BATCH=50
MICRO_RABBITMQ_PUBLISH_CONFIRM_MAX_WAIT_MS=10
Realistic Benchmark Natijalari
Muhim: Qisqa "burst" testlarda sun'iy yuqori raqamlar chiqadi. Quyidagi natijalar 5000–25000 xabarlik sustained load bilan o'lchangan (1 consumer, SQLite, prefetch_count=1):
| Workload | 5 000 xabar | 10 000 | 15 000 | 20 000 | 25 000 |
|---|---|---|---|---|---|
light (CPU only) |
238 eps | 211 | 219 | 211 | 215 |
db (INSERT) |
214 eps | 214 | 212 | 214 | 212 |
db_read (INSERT + SELECT) |
244 eps | 229 | 229 | 229 | 216 |
Asosiy xulosalar:
-
Haqiqiy bottleneck —
prefetch_count=1, handler emas.lightvadbworkload orasida farq atigi ~3 eps. Sababi:prefetch=1bilan consumer har bir xabarni ACK qilmasdan keyingisini ololmaydi — bu RabbitMQ round-trip latency ceiling ni belgilaydi (~215 eps). Handler ichida DB query bo'lsa ham bo'lmasa ham natija bir xil. -
Kichik testlardagi yuqori raqamlarga ishonmang. Burst rejimida (100–400 xabar) consumer tayyor xabarlarni oldindan o'qib, 900–1200 eps ko'rsatishi mumkin. Bu real sustained throughput emas.
-
Throughputni oshirish:
prefetch_countva consumer worker sonini oshiring:
MICRO_RABBITMQ_PREFETCH=20
# 4 ta parallel consumer
php artisan micro:consume &
php artisan micro:consume &
php artisan micro:consume &
php artisan micro:consume &
prefetch=20 + 4 consumer bilan taxminiy throughput: 215 × 4 × ~3 = ~2500 eps. Aniq raqam uchun o'z muhitingizda o'lchang.
🎧 3. Xabarlarni Qabul Qilish (Consumer)
MicroRabbit'da xabarlarni qabul qilish uchun config fayllarda marshrutlarni ro'yxatdan o'tkazish shart emas. Tizim PHP 8 Attributes orqali Auto-Discovery (o'zini-o'zi topish) xususiyatiga ega.
Default holatda micro:cache faqat base_path('app') ichini skan qiladi. Agar handlerlar boshqa joyda bo'lsa, config/micro-rabbitmq.php dagi paths array'iga qo'shib qo'ying.
Shunchaki istalgan papkada bitta Action klass yarating va unga atributlarni qo'shing:
namespace App\Actions;
use Azizdev\MicroRabbit\Attributes\ConsumeEvent;
use Azizdev\MicroRabbit\Attributes\MicroConfig;
#[ConsumeEvent(routingKey: 'order.created', queue: 'order_processing_queue', exchange: 'micro_events')]
#[MicroConfig(tries: 5, delayMs: 15000, retry: true)]
class OrderCreatedAction
{
public function handle(array $payload)
{
// 1. Kelgan datani o'qiymiz
$orderId = $payload['id'];
// 2. Biznes logikani bajaramiz
// ...
// 3. Agar RPC qilingan bo'lsa, Return yozish kifoya, MicroRabbit uni javob qilib qaytaradi!
return ['status' => 'success', 'processed_at' => now()];
}
}
Atributlar nima qiladi?
#[ConsumeEvent](Majburiy):routingKey: Qaysi nomdagi xatni eshitishi kerakligi (masalan:user.registered).queue: RabbitMQ da qaysi navbat yaratilishi kerakligi.exchange: Qaysi pochtadan kutayotgani (Default:micro_events).
#[MicroConfig](Ixtiyoriy): Worker charchab qolmasligi uchun xatoliklar qoidasi.tries: Agar kod xatolik (Exception) bersa, necha marta qayta urinish kerak? (Default: 3).delayMs: Qayta urinishlar orasida necha millisoniya kutish (uxlash) kerak? (Default: 10000 = 10 sek).retry: Qayta urinish tizimini umuman o'chirib qo'yish (falsebo'lsa, 1-xatodayoq qabristonga ketadi).
DIQQAT: Klassni yozib bo'lgach, tizim uni tanib olishi uchun doim keshni yangilang:
php artisan micro:cache
📨 4. Xabar Jo'natish (Publish)
Xabar jo'natish juda oddiy. Fasaddan foydalanamiz:
use Azizdev\MicroRabbit\Facades\MicroRabbit;
// Eng sodda usul:
MicroRabbit::publish('user.registered', [
'id' => 1,
'name' => 'Azizbek'
]);
Tizim bu xatga avtomatik ravishda trace_id, message_id va hozirgi timestamp ni qo'shib, xavfsiz tarzda o'rab jo'natadi.
⏱ 5. RPC - Sinxron Javob Kutish
Mikroxizmatlar orasida kimdandir tezkor ma'lumot olish kerak bo'lganda (Sinxron), biz request dan foydalanamiz.
Muammo: Agar narigi xizmat o'chib yotgan bo'lsa, oddiy tizimlar cheksiz kutib, serverni qotirib qo'yadi. MicroRabbit Yechimi: Qat'iy Taymer (Strict Timeout).
use Azizdev\MicroRabbit\Facades\MicroRabbit;
try {
// 3-parametr: 5 soniya kutish taymeri
$response = MicroRabbit::request('get.user.balance', ['user_id' => 7], 5);
echo "Foydalanuvchi balansi: " . $response['balance'];
} catch (\Exception $e) {
// Agar 5 soniyada javob kelmasa yoki narigi servis o'chgan bo'lsa
// Tizim qulab tushmaydi, balki chiroyli xatolik otadi!
return response()->json(['error' => 'To\'lov tizimi vaqtinchalik ishlamayapti'], 504);
}
⚡ 6. Circuit Breaker - Domino Qulashini To'xtatish
Muammo: user-service o'chib qoldi. Unga har bir RPC so'rov 5 soniya timeout bilan kutadi. Agar 100 ta concurrent so'rov bo'lsa — 100 × 5 soniya = server thread pool to'ladi va boshqa barcha xizmatlar ham ishlashdan to'xtaydi. Bu Cascading Failure (Domino qulashi).
MicroRabbit Yechimi: Circuit Breaker. Belgilangan miqdorda xato yig'ilsa, tizim o'sha routing key uchun RPC so'rovlarni RabbitMQ ga umuman yubormasdan, darhol xato qaytaradi. Thread pool saqlanadi.
[CLOSED] → 5 xato → [OPEN] → 30 soniya → [HALF-OPEN] → muvaffaqiyat → [CLOSED]
✅ Normal ❌ Blokli 🔍 Sinov ✅ Normal
use Azizdev\MicroRabbit\Facades\MicroRabbit;
try {
$balance = MicroRabbit::request('get.user.balance', ['user_id' => 7], 5);
} catch (\RuntimeException $e) {
// Circuit ochiq bo'lsa ham, timeout bo'lsa ham — bu catch ga tushadi
// $e->getMessage() da "Circuit Breaker" yoki "RPC Timeout" yozuvi bo'ladi
return response()->json(['error' => 'Balans xizmati vaqtincha mavjud emas'], 503);
}
Circuit Breaker avtomatik ishlaydi — dasturchi hech narsa qo'shimcha qilmaydi. .env orqali sozlanadi:
MICRO_RABBITMQ_CIRCUIT_BREAKER=true
MICRO_RABBITMQ_CB_THRESHOLD=5 # 5 ta xatoda circuit ochiladi
MICRO_RABBITMQ_CB_TIMEOUT=30 # 30 soniyadan keyin recovery probe o'tadi
Eslatma: Circuit Breaker faqat
request()(RPC) uchun ishlaydi. Oddiypublish()asinxron bo'lgani uchun unga circuit breaker kerak emas.
🛡 7. Transactional Outbox Pattern
Dahshatli ssenariy: Mijozdan pulni yechdingiz, bazaga yozdingiz. Endi RabbitMQ ga xat otayotganingizda server interneti uzildi. Mijozning puli ketdi, lekin xizmat ko'rsatilmadi!
Buning yagona yechimi — Outbox Pattern. .env da MICRO_RABBITMQ_OUTBOX=true qiling. Endi MicroRabbit::publish() havo orqali xat otmaydi, balki uni o'sha vaqtdagi Tranzaksiya bilan birga Bazaga yozib qo'yadi.
use Illuminate\Support\Facades\DB;
use Azizdev\MicroRabbit\Facades\MicroRabbit;
DB::transaction(function () use ($user) {
// 1. Pul yechiladi
$user->decrement('balance', 50000);
// 2. Xat bazadagi "micro_outbox" jadvaliga tushadi (Tarmoq uzilsa ham 0% xavf)
MicroRabbit::publish('payment.success', ['user_id' => $user->id]);
});
Bazada yig'ilgan xatlarni tinimsiz ravishda RabbitMQ ga otib turuvchi pochta xizmatini serveringizda (Supervisor orqali) yoqib qo'ying:
php artisan micro:outbox:work
Bu Worker RabbitMQ o'chib qolsa ham qulab tushmaydi. U ulanish tiklanishini kutadi va o'zini-o'zi tiklaydi (Auto-Recovery).
🧱 8. Chidamlilik va Himoya (Fault Tolerance)
Kutubxona "Arvoh" xatolardan quyidagicha himoyalangan:
- Idempotency: RabbitMQ adashib bitta xatni 2 marta jo'natib yuborsa ham, Worker qorovuli xatning ID sini eslab qoladi va 2-martasida uni ignor qiladi.
- Kutish Zali (Delayed Retry): Kodingiz API ga ulana olmay qulasa, worker xatni asrash uchun uni maxsus
_delayednavbatiga otadi. Xat u yerda masalan 10 soniya uxlaydi va yana asosiy navbatga qaytadi. - Qabriston (DLX - Dead Letter Exchange): Agar xat 3 marta urinib ham xatolik beraversa, boshqa sog'lom xatlarga xalaqit bermasligi uchun u
_failednavbatiga (Qabristonga) otib yuboriladi. - Circuit Breaker: RPC orqali murojaat qilingan xizmat o'chib qolsa, belgilangan xato chegarasidan keyin so'rovlar darhol rad etiladi. Thread pool to'lib qolmaydi, bitta xizmatning o'lishi qolganlarni olib ketmaydi (qarang: 6-bo'lim).
- Distributed Tracing (Auto):
MICRO_RABBITMQ_TRACING=truebo'lsa, kelgan xabardagitrace_idavtomatik ravishdaLog::withContext()orqali joriy handlerning barcha log yozuvlariga qo'shiladi. ELK/Loki da bitta so'rovni servisdan-servisga kuzatish uchun handler ichida hech narsa yozish shart emas.
Dasturchi xatoni to'g'rilagach, qabristondagi xatlarni bitta komanda bilan yana hayotga qaytarishi mumkin:
php artisan micro:retry {navbat_nomi}
🧪 9. Test Yozish (Faking)
MicroRabbit bilan Pest yoki PHPUnit orqali test yozish "Oltin Standart" darajasida. Test paytida haqiqiy RabbitMQ ga ulanib vaqt o'tkazmaysiz.
use Azizdev\MicroRabbit\Facades\MicroRabbit;
test('buyurtma tasdiqlanganda xat otilishi kerak', function () {
// 1. Qopqonni yoqamiz (Xatlar RabbitMQ o'rniga xotiraga tushadi)
MicroRabbit::fake();
// 2. Asosiy loyihaning mantiqiy qismi ishlaydi
$this->postJson('/api/orders/confirm', ['id' => 123]);
// 3. Xat aniq otilganiga ishonch hosil qilamiz
MicroRabbit::assertPublished('order.confirmed');
// 4. (Ixtiyoriy) Payload ichidagi datalarni chuqur tekshiramiz
MicroRabbit::assertPublished('order.confirmed', function ($payload) {
return $payload['id'] === 123;
});
// 5. Ortiqcha boshqa xat ketib qolmaganini tekshiramiz
MicroRabbit::assertNotPublished('order.failed');
});
💻 10. Konsol Komandalari
php artisan micro:cache—pathsbo'yicha attributlarni topib, yashin tezligida ishlashi uchun keshga yozadi. Doim kod o'zgarganda urilishi shart.php artisan micro:consume --queue={queue}— Event worker'ni ishga tushiradi.--queueberilmasa barcha topilgan navbatlarni tinglaydi.php artisan micro:outbox:work— Outbox pattern yoqilgan bo'lsa, bazadan xatlarni olib uzluksiz RabbitMQ ga otib turuvchi asosiy dvigatel.php artisan micro:retry {queue}—_failed(Qabriston) ga tushib qolgan xatlarni qaytadan ishlash uchun asosiy navbatga qaytaradi.php artisan micro:health— Outbox backlog, DLQ hajmi va publish timeout metrikalarini tekshiradi.