চেকপয়েন্ট সহ ইনক্রিমেন্টাল ডেটা সিঙ্ক: সিস্টেমগুলোকে নিরাপদে সঙ্গত রাখুন
চেকপয়েন্ট সহ ইনক্রিমেন্টাল ডেটা সিঙ্ক কার্সর, হ্যাশ এবং রিজিউম টোকেন ব্যবহার করে সিস্টেমগুলোকে সঙ্গত রাখে—পুনরায় ইমপোর্ট না করে নিরাপদে পুনরায় শুরু করতে দেয়।

কেন সবকিছু পুনরায় ইমপোর্ট করলে সমস্যা বারবার হয়
পূর্ণ পুনরায় ইমপোর্ট নিরাপদ মনে হয় কারণ এটি সহজ লাগায়: মুছে ফেলুন, পুনরায় লোড করুন, শেষ। বাস্তবে, এগুলো ধীর সিঙ্ক, বাড়তি বিল, এবং এলোমেলো ডেটার অন্যতম সহজ উপায়।
প্রথম সমস্যা হল সময় ও খরচ। প্রতি রানের সমস্ত ডেটাসেট বারবার টেনে নিলে আপনি একই রেকর্ডগুলো বারবার ডাউনলোড করেন। যদি আপনি রাতের ব্যাচে ৫০০,০০০ জন কাস্টমার সিঙ্ক করেন, তখন কেবলমাত্র ২০০ রেকর্ডই বদলালেও আপনি কম্পিউট, API কল এবং ডেটাবেস লেখার জন্য পে করবেন।
দ্বিতীয় সমস্যা হল সঠিকতা। পূর্ণ পুনরায় ইমপোর্ট প্রায়ই ডুপ্লিকেট তৈরি করে (কারণ মিলানোর নিয়ম আদর্শ নয়), অথবা নতুন এডিটগুলোকে পুরনো এক্সপোর্টেড ডেটার সাথে ওভাররাইট করে দেয়। অনেক দলও দেখেন যে টোটাল সময়ের সাথে ভেসে যায় কারণ “মুছে ফেলে পুনরায় লোড” মাঝপথে নিঃশব্দে ব্যর্থ হয়।
সাধারণ লক্ষণগুলো দেখতে এমন:
- রানের পরে সিস্টেমগুলোর মধ্যে কাউন্ট মেলেনা
- রেকর্ডগুলো ছোট ছোট ভিন্নতার সাথে দুইবার দেখা যায় (ইমেইল কেসিং, ফোন ফরম্যাটিং)
- সম্প্রতি আপডেট করা ফিল্ডগুলো পুরনো ভ্যালুতে ফিরে যায়
- সিঙ্ক কখনো কখনো “শেষ” হয় কিন্তু একটি অংশ মিস করে
- প্রতিটি ইমপোর্ট উইন্ডো পর পর সাপোর্ট টিকিট বাড়ে
চেকপয়েন্ট হল একটি ছোট সেভ করা মার্কার যা বলে, “আমি এখানে পর্যন্ত প্রসেস করেছি।” পরের বার আপনি সেই মার্কার থেকে চালিয়ে যান, শুরু থেকে নয়। মার্কার হতে পারে একটি টাইমস্ট্যাম্প, একটি রেকর্ড ID, একটি ভার্সন নম্বর, বা API থেকে আসে এমন একটি টোকেন।
আপনার বাস্তব লক্ষ্য যদি দুটি সিস্টেমকে সময়ের সাথে সঙ্গত রাখা হয়, তবে চেকপয়েন্ট সহ ইনক্রিমেন্টাল ডেটা সিঙ্ক সাধারণত ভালো লক্ষ্য। এটি বিশেষভাবে উপকারী যখন ডেটা ঘন ঘন পরিবর্তিত হয়, এক্সপোর্ট বড়, API-র রেট লিমিট আছে, অথবা আপনাকে ক্র্যাশের পরে নিরাপদে পুনরায় শুরু করতে হবে (উদাহরণ: আপনি একটি ইন্টার্নাল টুলে কাজ করছেন যা AppMaster-এর ওপর নির্মিত)।
পদ্ধতি চয়ন করার আগে সিঙ্ক লক্ষ্য নির্ধারণ করুন
চেকপয়েন্ট সহ ইনক্রিমেন্টাল ডেটা সিঙ্ক তখনই ভাল কাজ করে যখন আপনি পরিষ্কারভাবে জানেন “সঠিক” মানে কি। যদি আপনি এটি এড়িয়ে কেবল কার্সর বা হ্যাশে ঝাঁপিয়ে পড়েন, সাধারণত পরে পুনরায় সিঙ্কটি আবার তৈরি করতে হয় কারণ নিয়মগুলি লেখা হয়নি।
শুরু করুন সিস্টেমগুলোর নামকরণ করে এবং সিদ্ধান্ত নিয়ে কে ট্রুথের মালিক। উদাহরণস্বরূপ, আপনার CRM হতে পারে কাস্টমারের নাম ও ফোন নম্বরের সোর্স অফ ট্রুথ, আর বিলিং টুল হতে পারে সাবস্ক্রিপশন স্ট্যাটাসের সোর্স। যদি উভয় সিস্টেম একই ফিল্ডে এডিট করতে পারে, তাহলে আপনার কাছে একটি একক সোর্স নেই এবং আপনাকে কনফ্লিক্টের পরিকল্পনা করতে হবে।
এরপর নির্ধারণ করুন “সিঙ্ক করা” মানে কী। কি আপনাকে সবসময় একেবারে মিল রাখতে হবে, নাকি কয়েক মিনিটের মধ্যে আপডেট দেখলেই যথেষ্ট? একেবারে মিল মানে সাধারণত কঠোর অর্ডারিং, চেকপয়েন্টের উপর শক্ত উচ্চারিত গ্যারান্টি, এবং ডিলেটের বেশি সতর্ক হ্যান্ডলিং। ইভেন্টুয়াল কনসিস্টেন্সি সাধারণত সস্তা এবং অস্থায়ী ব্যর্থতার প্রতি সহনশীল।
সিঙ্কিংয়ের দিক নির্ধারণ করুন। এক-পথ সিঙ্ক সহজ: সিস্টেম A সিস্টেম B-কে দেয়। দুই-দিক সিঙ্ক কঠিন কারণ প্রতিটি আপডেট কনফ্লিক্ট হতে পারে, এবং আপনাকে এমনভাবে কাজ করতে হবে যাতে দুইপক্ষই পরপর “সামঞ্জস্য” করে করে লুপে না পড়ে।
নির্মাণের আগে উত্তর দেয়ার জন্য প্রশ্ন
সবাই মিলেই এমন সাধারণ নিয়মগুলো লিখে রাখুন:
- প্রতিটি ফিল্ড (বা অবজেক্ট টাইপ) জন্য কোন সিস্টেম সোর্স অফ ট্রুথ?
- কতোটা ল্যাগ গ্রহণযোগ্য (সোকেন্ড, মিনিট, ঘণ্টা)?
- এটি এক-পথ নাকি দুই-দিক, এবং কোন ইভেন্টগুলো কোন দিকে যায়?
- ডিলেট কিভাবে হ্যান্ডেল হবে (হার্ড ডিলেট, সফট ডিলেট, টোম্বস্টোন)?
- দুইপক্ষ একসাথে একই রেকর্ড পরিবর্তন করলে কী হবে?
একটি ব্যবহারিক কনফ্লিক্ট রুলসেট হতে পারে, “সাবস্ক্রিপশন ফিল্ডে বিলিং জিতবে, কনট্যাক্ট ফিল্ডে CRM জিতবে, নতুবা নতুনতম আপডেট জিতে যাবে।” যদি আপনি AppMaster-এর মত টুলে ইন্টিগ্রেশন তৈরি করেন, এই নিয়মগুলো Business Process লজিকে ধরুন যাতে সেগুলো দৃশ্যমান ও টেস্টেবল থাকে, কারও স্মৃতিতে আটকে না থাকে।
কার্সর, হ্যাশ, এবং রিজিউম টোকেন: নির্মাণ ব্লক
চেকপয়েন্ট সহ ইনক্রিমেন্টাল ডেটা সিঙ্ক সাধারণত তিনটি “পজিশন” এর মধ্যে একটি দ্বারা কাজ করে যা আপনি নিরাপদে সংরক্ষণ ও পুনরায় ব্যবহার করতে পারেন। সঠিক পছন্দ নির্ভর করে সোর্স সিস্টেম কি গ্যারান্টি দেয় এবং আপনাকে কোন ধরনের ব্যর্থতা বাঁচাতে হবে।
কার্সর চেকপয়েন্ট সবচেয়ে সহজ। আপনি সংরক্ষণ করেন “আমি শেষ যে জিনিসটি প্রসেস করেছি” — যেমন একটি শেষ ID, শেষ updated_at টাইমস্ট্যাম্প, বা একটি সিকোয়েন্স নম্বর। পরের রানে, সেই পয়েন্টের পরে রেকর্ডগুলি অনুরোধ করেন। এটি ভাল কাজ করে যখন সোর্স সঠিকভাবে সাজায় এবং ID বা টাইমস্ট্যাম্প বদলে সামনের দিকে চলে। এটি ভেঙে পড়ে যখন আপডেট পরে আসে, ঘড়ির সময় ভিন্ন হয়, বা রেকর্ড অতীতে ঢোকানো যায় (উদাহরণ: ব্যাকফিল করা ডেটা)।
হ্যাশ আপনাকে পরিবর্তন সনাক্ত করতে সাহায্য করে যেখানে কেবল কার্সর যথেষ্ট নয়। আপনি প্রতিটি রেকর্ডকে হ্যাশ করতে পারেন (যেসব ফিল্ড আপনি বিবেচনা করেন তাদের উপর ভিত্তি করে) এবং কেবল হ্যাশ বদলালে সিঙ্ক করুন। অথবা আপনি পুরো ব্যাচ হ্যাশ করে দ্রুত ড্রিফট ধরতে পারেন এবং তারপর বিস্তারিত দেখেন। প্রতিটি রেকর্ডের হ্যাশ সঠিক কিন্তু স্টোরেজ ও কম্পিউট বাড়ায়। ব্যাচ হ্যাশ সস্তা কিন্তু কোন আইটেম বদলেছে তা লুকাতে পারে।
রিজিউম টোকেন হলো সোর্স ইস্যুকৃত অপরদর্শী মান, প্রায়শই পেজিনেশন বা ইভেন্ট স্ট্রিমের জন্য। আপনি এগুলো বিশ্লেষণ করেন না, শুধুমাত্র সংরক্ষণ করে ফেরত পাঠান। টোকেন ভালো যখন API জটিল, কিন্তু এগুলো মেয়াদ শেষ হতে পারে, রিটেনশন উইন্ডোর পরে অকার্যকর হতে পারে, বা পরিবেশগুলোর মধ্যে ভিন্নভাবে আচরণ করতে পারে।
কোনটি ব্যবহার করবেন, এবং কী ভূল হতে পারে
- কার্সর: দ্রুত এবং সহজ, তবে আউট-অফ-অর্ডার আপডেট খেয়াল রাখুন।
- প্রতিটি রেকর্ড হ্যাশ: নির্ভুল পরিবর্তন সনাক্তকরণ, কিন্তু বেশি খরচসাপেক্ষ।
- ব্যাচ হ্যাশ: সস্তা ড্রিফট সিগন্যাল, কিন্তু নির্দিষ্ট নয় কোন আইটেম বদলেছে।
- রিজিউম টোকেন: নিরাপদ পেজিনেশন, কিন্তু মেয়াদ শেষ হওয়া বা একবার ব্যবহার হওয়ার সম্ভাব্যতা থাকে।
- হাইব্রিড (কার্সর + হ্যাশ): সাধারণ যখন
updated_atপুরোপুরি বিশ্বাসযোগ্য নয়।
যদি আপনি AppMaster-এর মত টুলে সিঙ্ক বানান, তবে এই চেকপয়েন্টগুলো সাধারণত একটি ছোট “sync state” টেবিলে থাকে, যাতে প্রতিটি রান অনুমান ছাড়া পুনরায় শুরু করতে পারে।
আপনার চেকপয়েন্ট স্টোরেজ ডিজাইন করা
চেকপয়েন্ট স্টোরেজই ছোট টুকরো যা ইনক্রিমেন্টাল ডেটা সিঙ্ককে নির্ভরযোগ্য করে তোলে। যদি এটি পড়তে কঠিন, ওভাররাইট করা সহজ, বা নির্দিষ্ট জবে না বেঁধে থাকে, আপনার সিঙ্ক একটি ভালো দেখাবে যতক্ষণ না এটি একবার ব্যর্থ হয়—তারপর আপনি অনুমান করবেন।
প্রথমে, নির্ধারণ করুন কোথায় চেকপয়েন্ট থাকবে। ডেটাবেস টেবিল সাধারণত সবচেয়ে নিরাপদ কারণ এটি লেনদেন, অডিটিং, এবং সহজ কুয়েরি সমর্থন করে। একটি কি-ভ্যালু স্টোর কাজ করতে পারে যদি আপনি ইতিমধ্যে সেটি ব্যবহার করেন এবং এটি অ্যাটমিক আপডেট সমর্থন করে। কনফিগ ফাইল কেবলমাত্র সিঙ্গেল-ইউজার, কম-ঝুঁকিপূর্ণ সিঙ্কের জন্য যুক্তিযুক্ত, কারণ এটি লক করা কঠিন এবং হারিয়ে যাওয়া সহজ।
কী সংরক্ষণ করবেন (এবং কেন)
একটি চেকপয়েন্ট কেবল কার্সর নয়। ডিবাগ, পুনরায় শুরু, এবং ড্রিফট সনাক্ত করার জন্য পর্যাপ্ত কনটেক্সট সেভ করুন:
- জব পরিচয়: জব নাম, টেন্যান্ট বা অ্যাকাউন্ট আইডি, অবজেক্ট টাইপ (যেমন, customers)
- প্রগ্রেস: কার্সর ভ্যালু বা রিজিউম টোকেন, এবং কার্সর টাইপ (time, id, token)
- হেলথ সিগন্যাল: শেষ রান সময়, স্ট্যাটাস, পড়া ও লেখা রেকর্ড সংখ্যা
- সেফটি: শেষ সফল কার্সর (শুধু শেষ চেষ্টা নয়), এবং সাম্প্রতিক ব্যর্থতার একটি সংক্ষিপ্ত ত্রুটি বার্তা
যদি আপনি পরিবর্তন সনাক্তকরণ হ্যাশ ব্যবহার করেন, তবে হ্যাশ মেথড ভার্সনও সংরক্ষণ করুন। না হলে পরেও হ্যাশ বদলে গেলে সবকিছু “পরিবর্তিত” মনে হতে পারে।
ভার্সনিং এবং বহু সিঙ্ক জব
আপনার ডেটা মডেল পরিবর্তিত হলে, আপনার চেকপয়েন্ট ভার্সন করুন। সহজ উপায় হল একটি schema_version ফিল্ড যোগ করে নতুন ভার্সনের জন্য নতুন সারি তৈরি করা, পুরোনো ডেটা পরিবর্তন না করে। কিছুদিন পুরোনো সারি রাখুন যাতে রোলব্যাক করা যায়।
বহু সিঙ্ক জব হলে, সবকিছু নামস্থান করুন। একটি ভাল কি হলো (tenant_id, integration_id, object_name, job_version)। এটি সেই ক্লাসিক বাগ এড়ায় যেখানে দুইটি জব একই কার্সর ভাগ করে এবং চুপচাপ ডেটা স্কিপ করে।
কনক্রিট উদাহরণ: যদি আপনি AppMaster-এ একটি ইন্টার্নাল টুল হিসেবে সিঙ্ক তৈরি করেন, PostgreSQL-এ প্রতিটি টেন্যান্ট ও অবজেক্টের জন্য একটি সারি সংরক্ষণ করুন, এবং সফল ব্যাচ কমিটের পরে এটিকে আপডেট করুন।
ধাপে ধাপে: ইনক্রিমেন্টাল সিঙ লুপ বাস্তবায়ন
একটি ইনক্রিমেন্টাল ডেটা সিঙ্ক চেকপয়েন্ট সহ তখনই সবচেয়ে ভাল কাজ করে যখন আপনার লুপ বিরক্তিকর এবং পূর্বাভাসযোগ্য। লক্ষ্য সহজ: স্থির অর্ডারে পরিবর্তন পড়ুন, নিরাপদভাবে লিখুন, তারপর আপনি জানেন যখন লেখা শেষ—একই সময়ে চেকপয়েন্ট অগ্রসর করুন।
একটি সহজ লুপ যা আপনি বিশ্বাস করতে পারেন
প্রথমে এমন একটি অর্ডারিং নির্বাচন করুন যা একই রেকর্ডের জন্য কখনো পরিবর্তিত হয় না। টাইমস্ট্যাম্প কাজ করতে পারে, কিন্তু শুধুমাত্র যদি আপনি একটি টাই-ব্রেকার (যেমন ID) যোগ করেন যাতে একই সময়ে দুইটি আপডেট নেড়ে না দেয়।
তারপর লুপ চালান এভাবে:
- আপনার কার্সর নির্ধারণ করুন (উদাহরণ: last_updated + id) এবং পেজ সাইজ ঠিক করুন।
- স্টোর করা চেকপয়েন্টের পরে নতুন পেজের রেকর্ডগুলো ফেচ করুন।
- প্রতিটি রেকর্ড টার্গেটে আপসার্ট করুন (নহলে তৈরি, উপস্থিত হলে আপডেট) এবং ব্যর্থতা ধরুন।
- সফল লেখাগুলো কমিট করুন, তারপর শেষ প্রসেস করা রেকর্ড থেকে নতুন চেকপয়েন্ট সেভ করুন।
- পুনরাবৃত্তি করুন। যদি পেজ খালি হয়, ঘুমান, তারপর আবার চেষ্টা করুন।
চেকপয়েন্ট আপডেটকে ফেচ থেকে আলাদা রাখুন। যদি আপনি চেকপয়েন্ট আগে সেভ করেন, একটি ক্র্যাশ ডেটা চুপচাপ স্কিপ করতে পারে।
ব্যাকঅফ এবং রিট্রাই ডুপ্লিকেট ছাড়া
ধারণা করুন কলগুলো ব্যর্থ হবে। যখন একটি ফেচ বা রাইট ব্যর্থ হয়, ছোট ব্যাকঅফ সহ রিট্রাই করুন (উদাহরণ: ১ সেকেন্ড, ২ সেকেন্ড, ৫ সেকেন্ড) এবং একটি সর্বোচ্চ রিট্রাই কাউন্ট রাখুন। রিট্রাইগুলো নিরাপদ করুন আপসার্ট ব্যবহার করে এবং আপনার রাইটগুলো আইডেমপটেন্ট করে (একই ইনপুট, একই ফল)।
একটি ছোট ব্যবহারিক উদাহরণ: যদি আপনি প্রতি মিনিটে কাস্টমার আপডেট সিঙ্ক করেন, আপনি হয়ত প্রতি বার ২০০ পরিবর্তন ফেচ করবেন, সেগুলো আপসার্ট করে শেষ কাস্টমারের (updated_at, id) কিউরসরের মতো নতুন কার্সর সংরক্ষণ করবেন।
AppMaster-এ এটি বানালে, আপনি চেকপয়েন্টকে একটি সাধারণ টেবিলে (Data Designer) মডেল করতে পারেন এবং একটি Business Process-এ লুপটি চালাতে পারেন যা ফেচ করে, আপসার্ট করে, এবং চেকপয়েন্ট নিয়ন্ত্রিতভাবে আপডেট করে।
রিজিউম নিরাপদ করুন: আইডেমপটেন্সি ও অ্যাটমিক চেকপয়েন্ট
আপনার সিঙ্ক পুনরায় শুরু করতে পারলে, এটি সবচেয়ে খারাপ সময়ে পুনরায় শুরু হবে: টাইমআউট, ক্র্যাশ, বা আংশিক ডিপ্লয়ের পরে। লক্ষ্য সহজ: একই ব্যাচ পুনরায় চালালে ডুপ্লিকেট তৈরি বা আপডেট হারানো হবে না।
আইডেমপটেন্সি হলো সেফটি নেট। এটি সাধারণত আপসার্ট দিয়ে আসে: ইনসার্ট না করে এমনভাবে লিখুন যা পুনরাবৃত্তিতে একই ফলাফল দেয়। বাস্তবে এর মানে একটি স্থায়ী কিওয়াই দিয়ে রেকর্ড লেখা (যেমন customer_id) এবং বিদ্যমান সারি থাকলে আপডেট করা।
একটি ভালো “রাইট কী” হলো এমন কিছু যা আপনি রিট্রাই জোরে বিশ্বাস করতে পারেন। সাধারণ অপশনগুলো হল সোর্স সিস্টেমের একটি ন্যাচারাল ID, অথবা প্রথম দেখা সময়ে আপনি যে সিন্থেটিক কী তৈরি করেন। একটি অনন্য কনস্ট্রেইন্ট ব্যাক করুন যাতে ডেটাবেস আপনার নিয়ম প্রয়োগ করে এমনকি দুই কাজী একসাথে রেস করলে।
অ্যাটমিক চেকপয়েন্টও ততটাই জরুরি। যদি আপনি ডেটা কমিট হওয়ার আগে কার্সর অগ্রসর করেন, একটি ক্র্যাশ আপনাকে রেকর্ড স্কিপ করে দিতে পারে। চেকপয়েন্ট আপডেটকে আপনার লেখার একই ইউনিট অফ ওয়ার্ক হিসেবে বিবেচনা করুন।
ইনক্রিমেন্টাল ডেটা সিঙ্কের জন্য একটি সাধারণ প্যাটার্ন:
- শেষ চেকপয়েন্ট থেকে পরিবর্তন পড়ুন (কার্সর বা টোকেন)।
- প্রতিটি রেকর্ড ডিডুপ কী ব্যবহার করে আপসার্ট করুন।
- ট্রানজেকশন কমিট করুন।
- তারপরই নতুন চেকপয়েন্ট সংরক্ষণ করুন।
আউট-অফ-অর্ডার আপডেট এবং পরে আসা ডেটা আরেকটি সাধারণ ফাঁদ। একটি রেকর্ড 10:01-এ আপডেট হলেও 10:02-এর পরে এসে পড়তে পারে, অথবা একটি API রিট্রাই-এ পুরনো চেঞ্জ ডেলিভার করতে পারে। নিজেকে রক্ষা করতে সোর্সের last_modified সংরক্ষণ করুন এবং “last write wins” নীতি প্রয়োগ করুন: ইনকামিং রেকর্ড যখন বর্তমানের চেয়ে নতুন তখনই ওভাররাইট করুন।
যদি আপনার বেশি সুরক্ষা দরকার, একটি ছোট ওভারল্যাপ উইন্ডো রাখুন (উদাহরণ: শেষ কয়েক মিনিট আবার পড়ুন) এবং আইডেমপটেন্ট আপসার্টে নির্ভর করুন যাতে রিপিটগুলো উপেক্ষা করা যায়। এটি একটু অতিরিক্ত কাজ বাড়ায়, কিন্তু পুনরায় শুরুকে বিরক্তিকর করে তোলে—যা আপনি চাইবেন।
AppMaster-এ একই ধারণা পরিষ্কারভাবে Business Process ফ্লোতে মানানসই: প্রথমে আপসার্ট লজিক, কমিট, তারপর শেষ ধাপে কার্সর বা রিজিউম টোকেন সংরক্ষণ করা।
ইনক্রিমেন্টাল সিঙ্ক ভাঙার সাধারণ ভুলগুলো
অধিকাংশ সিঙ্ক বাগ কোড নিয়ে নয়। সেগুলো কয়েকটি অনুমান থেকে আসে যা বাস্তব ডেটা এলে নিরাপদ মনে হলেও ভূল প্রমাণিত হয়। চেকপয়েন্ট সহ ইনক্রিমেন্টাল ডেটা সিঙ্ক দীর্ঘস্থায়ী রাখতে চাইলে এই ফাঁদগুলো আগে ধরুন।
সাধারণ ব্যর্থতার পয়েন্ট
একটি সাধারণ ভুল হল updated_at-কে অতিরিক্ত বিশ্বাস করা। কিছু সিস্টেম ব্যাকফিল, টাইমজোন ফিক্স, ব্যাচ এডিট, বা রিড-রিপেয়ার চলাকালে টাইমস্ট্যাম্প পুনরায় লেখে। যদি আপনার কার্সর কেবল একটি টাইমস্ট্যাম্প হয়, আপনি রেকর্ড মিস করতে পারেন (টাইমস্ট্যাম্প পিছনে যায়) বা বিশাল রেঞ্জ পুনরায় প্রসেস করতে পারেন (টাইমস্ট্যাম্প সামনে ঝাঁপ দেয়)।
আরেকটি ফাঁদ হল আইডিগুলো ধারাবাহিক বা কঠোরভাবে বাড়ছে ধরে নেওয়া। ইমপোর্ট, শার্ডিং, UUID, এবং ডিলিট করা সারি এই ধারণাকে ভাঙে। যদি আপনি “শেষ দেখা ID” কে চেকপয়েন্ট হিসেবে ব্যবহার করেন, গ্যাপ এবং আউট-অফ-অর্ডার লেখাগুলো রেকর্ড ফাঁকি রাখে।
সবচেয়ে ক্ষতিকর বাগ হল আংশিক সফলতার পরে চেকপয়েন্ট অগ্রসর করা। উদাহরণ: আপনি 1,000 রেকর্ড ফেচ করেন, 700 লিখেন, তারপর ক্র্যাশ করেন, কিন্তু আপনি এখনও ফেচ থেকে “নেক্সট কার্সর” সংরক্ষণ করেন। রিস্টার্টে বাকী 300 আর রিট্রাই হয় না।
ডিলেটগুলোও সহজে উপেক্ষা করা যায়। সোর্স হয়তো সফট-ডিলেট (ফ্ল্যাগ), হার্ড-ডিলেট (রো মুছে ফেলা), বা “অপ্রকাশ” (স্ট্যাটাস পরিবর্তন) করতে পারে। আপনি যদি কেবল অ্যাকটিভ রেকর্ড আপসার্ট করেন, টার্গেট ধীরে ধীরে ভেসে যাবে।
অবশেষে, স্কিমা পরিবর্তন পুরোনো হ্যাশগুলিকে অকার্যকর করতে পারে। যদি আপনার চেঞ্জ-ডিটেকশন হ্যাশ নির্দিষ্ট ফিল্ডের উপর তৈরি করা হয়, ফিল্ড যোগ বা নাম পরিবর্তন করলে “কোনো পরিবর্তন নেই” কে “পরিবর্তিত” হিসেবে দেখাতে পারে—অথবা উল্টোটা—যদি আপনি হ্যাশ লজিক ভার্সন না করেন।
নিচে কিছু নিরাপদ ডিফল্ট আছে:
- কাঁচা টাইমস্ট্যাম্পের চেয়ে মনোটোনিক কার্সর (ইভেন্ট ID, লগ পজিশন) পছন্দ করুন যদি সম্ভব হয়।
- চেকপয়েন্ট লেখাকে আপনার ডেটা লেখার সমস্যার সফলতার সেই সীমানার অংশ হিসেবে বিবেচনা করুন।
- ডিলেটগুলো স্পষ্টভাবে ট্র্যাক করুন (টোম্বস্টোন, স্ট্যাটাস ট্রানজিশন, বা নিয়মিত রিকনসাইল)।
- আপনার হ্যাশ ইনপুট ভার্সন করুন এবং পুরোনো ভার্সন পড়ার যোগ্য রাখুন।
- সোর্স যদি রি-অর্ডার করতে পারে, একটি ছোট ওভারল্যাপ উইন্ডো যোগ করুন (শেষ N আইটেম আবার পড়ুন)।
AppMaster-এ এটি করলে, চেকপয়েন্টকে Data Designer-এ আলাদা টেবিল হিসেবে মডেল করুন এবং “ডাটা লিখুন + চেকপয়েন্ট লিখুন” ধাপটিকে একক Business Process রানের মধ্যে রাখুন, যাতে রিট্রাই করলে কাজ স্কিপ না করে।
মনিটরিং এবং ড্রিফট ডিটেকশন শব্দময় না করে রাখা
চেকপয়েন্ট সহ ইনক্রিমেন্টাল ডেটা সিঙ্কের জন্য ভালো মনিটরিং মানে “আরও লগ” নয়, বরং কয়েকটি নির্ভরযোগ্য সংখ্যার উপর নির্ভর করা। যদি আপনি উত্তর দিতে পারেন “আমরা কি প্রসেস করেছি, কত সময় লেগেছে, এবং আমরা কোথা থেকে পুনরায় শুরু করব?”, আপনি প্রায় সব ইস্যু কয় মিনিটে ডিবাগ করতে পারবেন।
প্রতিটি সিঙ্ক এক্সিকিউটের সময় একটি সঙ্কুচিত রান রেকর্ড লিখুন। এটি নিয়মিত রাখুন যাতে রানের তুলনা করে ট্রেন্ড দেখা যায়।
- শুরু কার্সর (বা রিজিউম টোকেন) এবং শেষ কার্সর
- ফেচ করা রেকর্ড, লেখা রেকর্ড, স্কিপ করা রেকর্ড
- রান সময়কাল এবং প্রতি রেকর্ড (বা প্রতি পেজ) গড় সময়
- ত্রুটি গণনা এবং শীর্ষ ত্রুটি কারণ
- চেকপয়েন্ট লেখার স্ট্যাটাস (সফল/ব্যর্থ)
ড্রিফট ডিটেকশন হলো পরবর্তী স্তর: এটি বলে যখন সিস্টেমগুলো “দু’জনেই কাজ করছে” কিন্তু ধীরে ধীরে ভিন্নমতে যাচ্ছে। কেবল মোটগুলো বিভ্রান্তিকর হতে পারে, তাই একটি হালকা মোট চেকের সাথে ছোট স্পট চেক মিলিয়ে নিন। উদাহরণস্বরূপ, দিনে একবার দুই সিস্টেমে সক্রিয় কাস্টমারের মোট মিলান করুন, তারপর ২০টি রেন্ডম কাস্টমার আইডির নমুনা নিয়ে কয়েকটি ফিল্ড মিলছে কি না নিশ্চিত করুন (status, updated_at, email)। যদি মোট ভিন্ন হয় কিন্তু নমুনা মিলে যায়, আপনি হয়ত ডিলেট বা ফিল্টার মিস করছেন। যদি নমুনা ভিন্ন হয়, আপনার চেঞ্জ-ডিটেকশন হ্যাশ বা ফিল্ড ম্যাপিং খারাপ হওয়ার সম্ভাবনা বেশি।
অ্যালার্টগুলো বিরল এবং কার্যকর হওয়া উচিত। একটি সহজ নিয়ম: শুধুমাত্র তখনই অ্যালার্ট করুন যখন একটি মানুষকে এখনই হস্তক্ষেপ করতে হবে।
- কার্সর আটকে গেছে (শেষ কার্সর N রান ধরে না চলছে)
- ত্রুটি হার বাড়ছে (উদাহরণ: ১% -> ৫% এক ঘন্টার মধ্যে)
- রান ধীর হয়ে গেছে (আপনার স্বাভাবিক ছাদের বেশি)
- ব্যাকলগ বাড়ছে (নতুন চেঞ্জ আসছে দ্রুত, কিন্তু আপনি সিঙ্ক করতে পারছেন না)
- ড্রিফট নিশ্চিত (দুইটি চেকে টোটাল মেলেনা)
ব্যর্থতার পরে, ম্যানুয়াল ক্লিনআপ ছাড়া নিরাপদে রিকভার করুন। সহজ উপায় হল সর্বশেষ কমিটেড চেকপয়েন্ট থেকে পুনরায় শুরু করা, “শেষ দেখা” রেকর্ড থেকে নয়। যদি আপনি একটি ছোট ওভারল্যাপ উইন্ডো ব্যবহার করেন (চূড়ান্ত পেজ আবার পড়া), তখন রাইটগুলো আইডেমপটেন্ট রাখুন: স্থিতিশীল আইডি দিয়ে আপসার্ট করুন এবং লেখাগুলো সফল হওয়ার পরে মাত্র চেকপয়েন্ট অগ্রসর করুন। AppMaster-এ দলরা প্রায়ই এসব চেক একটি Business Process ফ্লোতে বাস্তবায়ন করে এবং ইমেইল/SMS বা Telegram মডিউলের মাধ্যমে অ্যালার্ট পাঠায় যাতে ব্যর্থতাগুলো ড্যাশবোর্ড না দেখে ও দেখা যায়।
শিপ করার আগে দ্রুত চেকলিস্ট
প্রোডাকশন-এ চেকপয়েন্ট সহ ইনক্রিমেন্টাল ডেটা সিঙ্ক চালু করার আগে কিছু ছোট কিন্তু সাধারণ কারণে দেরি হওয়া সার্কেলগুলো চেক করে নিন। এই চেকগুলো কয় মিনিট সময় নেয়, কিন্তু “কেন আমরা রেকর্ড মিস করলাম?” ডিবাগিং-এ দিনগুলো রোধ করে।
প্রয়োগের আগে একটি বাস্তবিক চেকলিস্ট:
- যে ফিল্ড আপনি অর্ডারিং জন্য ব্যবহার করবেন (টাইমস্ট্যাম্প, সিকোয়েন্স, ID) তা নিশ্চিত করুন সত্যিই স্থির এবং সোর্স সাইডে ইনডেক্স আছে। যদি এটা পরে বদলে যায়, আপনার কার্সর ড্রিফট করবে।
- নিশ্চিত করুন আপনার আপসার্ট কী একচেটিয়া এবং দুই সিস্টেম এটিকে একইভাবে মোকাবেলা করে (কেস সেনসিটিভিটি, ট্রিমিং, ফরম্যাটিং)। যদি এক সিস্টেম "ABC" এবং অন্যটি "abc" রাখে, ডুপ্লিকেট হবে।
- প্রতিটি জব ও প্রতিটি ডেটাসেটের জন্য চেকপয়েন্ট আলাদা রাখুন। একটা “গ্লোবাল লাস্ট কার্সর” সহজ শোনায়, কিন্তু এটা ভেঙে যায় যতক্ষণ আপনি দুই টেবিল, দুই টেনেন্ট, বা দুই ফিল্টার সিঙ্ক করেন।
- সোর্স যদি ইভেন্টুয়ালি কনসিসটেন্ট হয়, একটি ছোট ওভারল্যাপ উইন্ডো যোগ করুন। উদাহরণ: যদি রি-শুরু থেকে "last_updated = 10:00:00" হয়, 09:59:30 থেকে পুনরায় শুরু করুন এবং আইডেমপটেন্ট আপসার্টে রিপিট অগ্রাহ্য করুন।
- একটি হালকা রিকনসাইল পরিকল্পনা করুন: নির্ধারিত সময়ে একটি ছোট নমুনা (যেমন 100 র্যান্ডম রেকর্ড) নিয়ে কী ফিল্ড মিলছে তা তুলনা করুন যাতে নীরব ড্রিফট ধরা পড়ে।
একটি বাস্তবতা টেস্ট: রান মাঝপথে পজ করুন, রিস্টার্ট করুন, এবং নিশ্চিত করুন একই ফলাফল পাবেন। যদি রিস্টার্ট করলে কাউন্ট বদলে যায় বা অতিরিক্ত রো তৈরি হয়, লঞ্চের আগে সেটি ঠিক করুন।
AppMaster-এ সিঙ্ক বানালে, প্রতিটি ইন্টিগ্রেশন ফ্লোর চেকপয়েন্ট ডেটা নির্দিষ্ট প্রসেস ও ডেটাসেটের সাথে বেঁধে রাখুন, অসম্পৃক্ত অটোমেশনগুলোর সাথে শেয়ার করবেন না।
উদাহরণ: দুই অ্যাপের মধ্যে কাস্টমার রেকর্ড সিঙ্ক করা
একটি সরল সেটআপ ভাবুন: আপনার CRM হলো কন্টাক্টগুলোর সোর্স অফ ট্রুথ, এবং আপনি একই ব্যক্তিদের একটি সাপোর্ট টুলে দেখতে চান (তাহলে টিকিটগুলো বাস্তব কাস্টমারের সাথে ম্যাচ করে) বা একটি কাস্টমার পোর্টালে (তাই ইউজাররা লগইন করে তাদের অ্যাকাউন্ট দেখতে পায়)।
প্রথম রানে, একটি এককালীন ইমপোর্ট করুন। কনট্যাক্ট গুলো একটি স্থির অর্ডনে টানুন, উদাহরণস্বরূপ updated_at প্লাস id কে টাই-ব্রেকার হিসেবে ব্যবহার করুন। প্রতিটি ব্যাচ লেখার পরে, একটি চেকপয়েন্ট সেভ করুন যেমন: last_updated_at এবং last_id. এই চেকপয়েন্ট ভবিষ্যত প্রতিটি রান-এর জন্য আপনার শুরু হওয়ার লাইন।
চলমান রানের জন্য, কেবল চেকপয়েন্টের পরে থাকা রেকর্ডগুলো ফেচ করুন। আপডেটগুলো সরাসরি: যদি CRM কনট্যাক্ট ইতিমধ্যে থাকে, টার্গেট রেকর্ড আপডেট করুন; না হলে তৈরি করুন। মার্জ হওয়া সমস্যা হলো ট্রিকি অংশ। CRM প্রায়ই ডুপ্লিকেট মার্জ করে একটি জয়ী কনট্যাক্ট রাখে। এটাকে একটি আপডেট হিসেবে দেখুন যা “পরাজিত” কনট্যাক্টকে নিষ্ক্রিয় করে (অথবা বিজয়ীর সাথে ম্যাপ করে) যাতে পোর্টালে একই ব্যক্তির জন্য দুইটি ইউজার না হয়ে যায়।
ডিলিশন সাধারণত সাধারণ "updated since" কুয়েরিতে আসে না, তাই এর পরিকল্পনা করুন। সাধারণ অপশনগুলো হল সোর্সে একটি সফট-ডিলেট ফ্ল্যাগ, একটি পৃথক "deleted contacts" ফিড, অথবা একটি নিয়মিত হালকা রিকনসিলিয়েশন যা অনুপস্থিত ID-গুলো চেক করে।
এখন ব্যর্থতার কেস: সিঙ্ক মাঝপথে ক্র্যাশ করে। আপনি যদি কেবল শেষে চেকপয়েন্ট রাখেন, আপনি একটি বিশাল চাংশ পুনপ্রক্রিয়া করবেন। পরিবর্তে, ব্যাচ-ভিত্তিক একটি রিজিউম টোকেন ব্যবহার করুন।
- একটি রান শুরু করুন এবং একটি
run_id(আপনার রিজিউম টোকেন) জেনারেট করুন - একটি ব্যাচ প্রসেস করুন, গন্তব্যে পরিবর্তন লিখুন, তারপর এটিকে অ্যাটমিকভাবে
run_id-এর সাথে বেঁধে চেকপয়েন্ট সেভ করুন - রিস্টার্টে, সেই
run_id-এর জন্য শেষ সেভ করা চেকপয়েন্ট খুঁজে বের করুন এবং সেখান থেকে চালিয়ে যান
সাফল্য বিরক্তিকর দেখায়: দৈনিক কাউন্ট স্থির থাকে, রানটাইম পূর্বাভাসযোগ্য, এবং একই উইন্ডো আবার চালালে কোন অপ্রত্যাশিত পরিবর্তন আসে না।
পরবর্তী ধাপ: একটি প্যাটার্ন চয়ন করুন এবং কম রিওয়ার্কে তা বানান
একবার আপনার প্রথম ইনক্রিমেন্টাল লুপ কাজ করতে শুরু করলে, দ্রুত পুনরায় কাজ এড়ানোর দ্রুত উপায় হল সিঙ্কের নিয়মগুলো লিখে রাখা। সংক্ষিপ্ত রাখুন: কোন রেকর্ড স্কোপে, কনফ্লিক্টে কোন ফিল্ড জিতে, এবং প্রতিটি রান শেষে কী “ডান” মনে হবে।
ছোট দিয়ে শুরু করুন। একটি ডেটাসেট বেছে নিন (যেমন customers) এবং এটি end-to-end চালান: প্রাথমিক ইমপোর্ট, ইনক্রিমেন্টাল আপডেট, ডিলেট, এবং একটি ইচ্ছাকৃত ব্যর্থতার পরে রিজিউম। এখনই অনুমানগুলো ঠিক করা সহজ, পাঁচটি টেবিল যুক্ত করার পরে নয়।
কখনও কখনও পুরো পুনর্নির্মাণই সঠিক সিদ্ধান্ত। তখন করুন যখন চেকপয়েন্ট স্টেট দুর্নীতিগ্রস্ত, আইডেন্টিফায়ার পরিবর্তন, বা একটি স্কিমা পরিবর্তন আপনার চেঞ্জ-ডিটেকশন ভেঙে দেয় (উদাহরণ: আপনি হ্যাশ ব্যবহার করছিলেন এবং ফিল্ডগুলোর মানে বদলে গেছে)। যদি আপনি পুনরায় ইমপোর্ট করেন, এটি একটি নিয়ন্ত্রিত অপারেশন হিসেবে করুন, হঠাৎ জরুরি বোতাম হিসেবে নয়।
নিরাপদভাবে রিইমপোর্ট করার উপায়:
- একটি ছায়া টেবিল বা প্যারালাল ডেটাসেটে ইমপোর্ট করুন, বর্তমানটি লাইভ রেখে দিন।
- কাউন্ট ভ্যালিডেট করুন এবং নমুনা পরীক্ষণ করুন, এজ কেসসহ (নাল, মার্জ ডেটা)।
- সম্পর্কগুলো ব্যাকফিল করুন, তারপর এক পরিকল্পিত কাটওভারে রিডারগুলো নতুন ডেটাসেটের দিকে সোয়াচ করুন।
- পুরনো ডেটাসেট একটি ছোট রোলব্যাক উইন্ডোর জন্য রাখুন, তারপর ক্লিনআপ করুন।
আপনি যদি কোড না লিখেই এটি গঠন করতে চান, AppMaster আপনাকে সব অংশ এক জায়গায় রাখতে সাহায্য করতে পারে: Data Designer-এ PostgreSQL-এ ডেটা মডেল করুন, Business Process Editor-এ সিঙ্ক নিয়ম নির্ধারণ করুন, এবং নির্ধারিত জব চালান যা রেকর্ড টানবে, ট্রান্সফর্ম করবে, এবং আপসার্ট করবে। AppMaster রিকোয়ারমেন্ট বদলালে পরিষ্কার কোড পুনর্উত্পাদন করে, ফলে “আরো একটি ফিল্ড যোগ করতে হবে” কম ঝুঁকিপূর্ণ হয়।
বেশিরভাগ ডেটাসেট বাড়ানোর আগে, আপনার সিঙ্ক কনট্র্যাক্ট ডকুমেন্ট করুন, একটি প্যাটার্ন (কার্সর, রিজিউম টোকেন, বা হ্যাশ) বেছে নিন, এবং একটি সিঙ্ক সম্পূর্ণরূপে নির্ভরযোগ্য করুন। তারপর একই কাঠামো পরবর্তী ডেটাসেটেও পুনরায় ব্যবহার করুন। দ্রুত টেস্ট করতে, একটি অ্যাপ্লিকেশন AppMaster-এ তৈরি করুন এবং প্রথমে একটি ছোট নির্ধারিত সিঙ্ক জব চালান।


