আমি কীভাবে একটি 'Set It and Forget It' সিঙ্ক সিস্টেম তৈরি করেছি

পণ্যের দাম অনেক জায়গায় পরিবর্তিত হয়। এগুলো অ্যাডমিন প্যানেলে, বাল্ক ইমপোর্টের (bulk imports) মাধ্যমে, অথবা API ওয়েবহুকের (webhooks) মাধ্যমে পরিবর্তিত হতে পারে।

আপনি যদি এই পরিবর্তনগুলো কোনো এক্সটার্নাল মার্কেটপ্লেসের সাথে সিঙ্ক করতে চান, তবে আপনি একটি সমস্যার সম্মুখীন হবেন। প্রতিটি কোড পাথে (code path) একটি করে সিঙ্ক কল যোগ করা একটি ভুল। আপনি কোনো একটি ভুলে যাবেন। কোনো একটি ভেঙে ফেলবেন। রক্ষণাবেক্ষণ (maintenance) একটি দুঃস্বপ্নে পরিণত হবে।

Django signals এটি সমাধান করে। আপনি মডেল সেভ (model save) ইভেন্টের সাথে এটি যুক্ত করতে পারেন। এটি এক জায়গাতেই প্রতিটি পরিবর্তন শনাক্ত করতে পারে।

কিন্তু signals-এর একটি ত্রুটি আছে। আপনি যদি একসাথে ১০০টি দাম আপডেট করেন, তবে signal ১০০ বার ফায়ার (fire) হবে। এর ফলে ১০০টি API কল ট্রিগার হবে। এতে আপনি রেট লিমিটে (rate limits) পৌঁছে যাবেন অথবা রিসোর্স অপচয় করবেন।

এটি ঠিক করার জন্য আমি একটি তিন-স্তর বিশিষ্ট প্যাটার্ন ব্যবহার করি:

• একটি signal handler যা তাৎক্ষণিকভাবে কাজ করার পরিবর্তে ID সংগ্রহ করে। • ডুপ্লিকেট সরানোর জন্য একটি per-thread set। • সবকিছু একসাথে প্রসেস করার জন্য transaction.on_commit ব্যবহার করে একটি flush callback।

এটি যেভাবে কাজ করে তা নিচে দেওয়া হলো।

  1. threading.local() ব্যবহার করুন গ্লোবাল ভেরিয়েবল (global variable) ব্যবহার করবেন না। গ্লোবাল ভেরিয়েবলগুলো রিকোয়েস্টের মধ্যে স্টেট (state) শেয়ার করে। এর ফলে ডেটা লিকেজ (data leakage) হতে পারে। threading.local() ডেটাকে একটি সিঙ্গেল থ্রেডের মধ্যে আইসোলেটেড (isolated) রাখে।

  2. রেকর্ড করুন, কাজ করবেন না signal handlerটি কেবল একটি set-এ প্রোডাক্ট ID যোগ করে। এরপর এটি Django-কে নির্দেশ দেয় যেন ডাটাবেস ট্রানজ্যাকশন (database transaction) সফল হওয়ার পরেই কেবল একটি flush ফাংশন চালানো হয়। এটি সেই ডেটা সিঙ্ক করা থেকে বিরত রাখে যা সেভ করতে ব্যর্থ হয়েছে।

  3. কাজগুলোকে ব্যাচ (batch) আকারে করুন যখন ট্রানজ্যাকশন কমিট (commit) হয়, তখন flush ফাংশনটি চলে। এটি set-টি কপি করে এবং সেটি খালি করে দেয়। এরপর এটি সম্পূর্ণ ID লিস্টটি একটি service layer-এ পাঠিয়ে দেয়।

service layer-টি সমস্ত প্রোডাক্ট আনার জন্য একটি মাত্র bulk query চালায়। এটি সেগুলোকে স্টোর অনুযায়ী গ্রুপ করে। সবশেষে, এটি প্রতিটি স্টোরের জন্য Celery-তে একটি মাত্র টাস্ক পাঠায়।

এর সুবিধাগুলো স্পষ্ট:

আপনি সিস্টেমটি একবার তৈরি করবেন। পরবর্তীতে আপনি যে নতুন ফিচারই যোগ করুন না কেন, তা স্বয়ংক্রিয়ভাবে এই সিঙ্ক সিস্টেমের সাথে কাজ করবে।

আপনি Django-তে এক্সটার্নাল API সিঙ্ক কীভাবে হ্যান্ডেল করেন? আপনি কি signals ব্যবহার করেন নাকি অন্য কোনো প্যাটার্ন?

উৎস: https://dev.to/acel/how-i-built-a-set-it-and-forget-it-sync-system-with-django-signals-2ld7