🔥 داده های تکراری را متوقف کنید! چگونه قفل های Redis برنامه ما را از هرج و مرج Firestore Trigger ذخیره کرد

سلام ، توسعه دهندگان دیگر! 👋 امروز ، من می خواهم یک مشکل دشوار را که با Firestore Bridgers روبرو شدم و اینکه چگونه قفل های Redis در روز نجات یافت ، به اشتراک بگذارم. اگر سیستم های توزیع شده را روی چندین سرور اجرا می کنید ، این یکی برای شما است.
مشکل: داده های تکراری از Firestore محرک است
در درخواست ما ، ما یک ماشه آتش نشانی داشتیم که هر زمان که یک سند جدید ایجاد می شد ، آتش می گرفت. قرار بود این ماشه داده ها را پردازش کرده و آن را در ما وارد کند items
جدول به اندازه کافی ساده ، درست است؟
در اینجا تنظیم اولیه ما به نظر می رسد:
const admin = require('firebase-admin');
const db = admin.firestore();
exports.onItemCreated = db.collection('items').onCreate(async (snap, context) => {
const newItem = snap.data();
try {
// Initially, we just inserted the data directly
await insertIntoItemsTable(newItem);
} catch (error) {
console.error('Error processing item:', error);
}
});
پیچش طرح: چندین نمونه EC2
همه چیز خوب کار کرد تا اینکه به دو نمونه EC2 رسیدیم. سپس متوجه چیزی عجیب شدیم – ورودی های تکراری در ما items
جدول مشکل؟ ماشه Firestore ما به طور همزمان در هر دو نمونه EC2 اجرا می شد ، و محدودیت های پایگاه داده ما برای جلوگیری از کپی ها کافی نبود.
قفل های redis را وارد کنید: راه حل
در اینجا نحوه رفع آن با استفاده از قفل های Redis آمده است:
const Redis = require('ioredis');
const admin = require('firebase-admin');
const redis = new Redis({
host: 'your-redis-host',
port: 6379
});
const db = admin.firestore();
exports.onItemCreated = db.collection('items').onCreate(async (snap, context) => {
const newItem = snap.data();
const documentId = snap.id;
const lockKey = `lock:firestore:item:${documentId}`;
try {
// Try to acquire the lock
const acquired = await redis.set(
lockKey,
'locked',
'NX', // Only set if key doesn't exist
'EX', // Set expiry
30 // 30 seconds expiry
);
if (!acquired) {
console.log(`Lock already acquired for document ${documentId}`);
return;
}
// Now safely process and insert the item
await insertIntoItemsTable(newItem);
// Release the lock after successful processing
await redis.del(lockKey);
} catch (error) {
console.error('Error processing item:', error);
// Make sure to release the lock even if processing fails
await redis.del(lockKey);
}
});
async function insertIntoItemsTable(item) {
// Your database insertion logic here
// This will only run on one EC2 instance now!
}
چرا این کار می کند
- قفل منحصر به فرد در هر سند: ما با استفاده از شناسه سند Firestore یک قفل منحصر به فرد Redis ایجاد می کنیم.
- اول بیا ، اولین بار خدمت کرد: فقط اولین نمونه EC2 که قفل را به دست می آورد ، سند را انجام می دهد.
- پاکسازی خودکار: 30 ثانیه انقضا تضمین می کند که قفل ها حتی اگر روند ما خراب شود ، آزاد می شوند.
- انتشار ایمن: ما همیشه قفل را آزاد می کنیم که پردازش موفق شود یا شکست بخورد.
نتایج در تولید
پس از اجرای این راه حل:
- ورودی های کپی صفر در جدول موارد ما
- سیاهههای مربوط به پردازش تمیز
- عدم تناقض داده دیگر
- استفاده بهتر از منابع (بدون پردازش هدر رفته)
یادگیری کلیدی
- همیشه توزیع را در نظر بگیرید: حتی محرک های ساده می توانند باعث ایجاد مشکلات در محیط های توزیع شده شوند.
- محدودیت های پایگاه داده همیشه کافی نیستند: گاهی اوقات به قفل سطح برنامه نیاز دارید.
- مدت زمان قفل بسیار مهم است: زمان انقضا را انتخاب کنید که طولانی ترین زمان پردازش ممکن شما را در بر می گیرد.
- کنترل قفل را کنترل کنید: در صورت دستیابی به قفل ها برای ردیابی مسائل احتمالی ، ورود به سیستم را وارد کنید.
نکاتی برای اجرای
- با استفاده از خطای خوب از مشتری redis استفاده کنید
- نظارت مناسب را برای خرابی در دستیابی به قفل اجرا کنید
- زمان قفل را به اندازه کاربردی کوتاه نگه دارید
- در فرآیندهای بحرانی ، منطق آزمایش مجدد را برای دستیابی به قفل در نظر بگیرید
آیا با محرک های Firestore یا پردازش توزیع شده با چالش های مشابه روبرو شده اید؟ دوست دارم داستانهای شما را در نظرات بشنوم!
برنامه نویسی مبارک! 🚀