মূল কনটেন্টে যান
Abdullah Al Rafi
মেনু

ট্রিয়ার, জার্মানি · CET

Lazy Termin: অ্যাপয়েন্টমেন্টের নোটিফিকেশন, যা কখনো দুবার আসে না

একটি Selenium চেকার, যা জার্মানির একটি অ্যাপয়েন্টমেন্ট বুকিং পেজ নজরে রাখে এবং PostgreSQL আউটবক্সের মাধ্যমে যাচাই করা সাবস্ক্রাইবারদের টেলিগ্রামে জানায়।

সারসংক্ষেপ

ভূমিকা
একক ডেভেলপার
সময়কাল
আগ ২০২৬ – বর্তমান
প্রযুক্তি
Python · Selenium · PostgreSQL · python-telegram-bot · Amazon SES · Docker Compose · GitHub Actions

41

আসল PostgreSQL-এর বিপরীতে ইউনিট টেস্ট

≤1

প্রতি কুলডাউনে সাবস্ক্রাইবারপ্রতি নোটিফিকেশন

ডিফল্ট কুলডাউন ৬০ মিনিট

3

অ্যাডমিনকে জানানোর আগে ডেলিভারির চেষ্টা

এই পেজে
  1. সারসংক্ষেপ
  2. সমস্যা
  3. সীমাবদ্ধতা
  4. পদ্ধতি ও আর্কিটেকচার
  5. ফলাফল
  6. এখন হলে যা অন্যভাবে করতাম

সমস্যা

জার্মানিতে অনেক সরকারি অফিস অনলাইন বুকিং পেজের মাধ্যমে অ্যাপয়েন্টমেন্ট (Termine) দেয়। খালি স্লট আসে অনিশ্চিতভাবে আর দ্রুত শেষ হয়ে যায়, তাই একটি পেতে হলে একই বহুধাপের বুকিং প্রক্রিয়া বারবার পার হতে হয়। Lazy Termin এই খোঁজার কাজটা করে দেয় এবং স্লট খালি হওয়ামাত্র জানিয়ে দেয়। বুকিং মানুষ নিজেই করেন অফিসিয়াল সাইটে।

সীমাবদ্ধতা

  • ভদ্রভাবে চলা। চেকার সাধারণ বুকিং প্রক্রিয়াই অনুসরণ করে, প্রতিটি ধাপের মাঝে এলোমেলোভাবে এক থেকে তিন সেকেন্ড অপেক্ষা করে, এবং কখনো CAPTCHA, রেট লিমিট বা লগইন এড়িয়ে যায় না। নিজে কখনো কিছু বুক করে না। নির্ধারিত রান হয় কর্মদিবসে অফিস সময়ে প্রতি ১৫ মিনিটে (Europe/Berlin)।
  • কোনো নোটিফিকেশন হারাবে না, দুবারও যাবে না। চেকার আর টেলিগ্রাম বট আলাদা প্রসেস, আর যেকোনোটি যেকোনো সময় রিস্টার্ট হতে পারে।
  • স্প্যাম নয়। প্রতিটি সাবস্ক্রাইবার প্রতি কুলডাউনে সর্বোচ্চ একটি নোটিফিকেশন পান, ডিফল্টভাবে ৬০ মিনিট।
  • ছোট ও আসল ব্যবহারকারী। সাবস্ক্রাইব করতে অনুমোদিত ডোমেইনের একটি ইমেইল ঠিকানা লাগে, যা Amazon SES-এ পাঠানো এককালীন কোড দিয়ে যাচাই হয়। সাবস্ক্রিপশনের সংখ্যা সীমিত, আর পাঁচ দিন পর মেয়াদ শেষ হয়।
  • যত কম সম্ভব তথ্য। মেসেজ টেলিমেট্রিতে থাকে শুধু সময়, টেলিগ্রাম ইউজার আইডি আর মেসেজের ধরন; মেসেজের লেখা কখনো নয়।

পদ্ধতি ও আর্কিটেকচার

    • Docker Compose-এ cron

      শিডিউল

      প্রতি ১৫ মিনিটে, কর্মদিবসে ০৭:০০–১৬:৪৫, Europe/Berlin

    • GitHub Actions

      শিডিউল

      কর্মদিবসের নির্দিষ্ট সময়ে, অথবা হাতে চালু করে

  1. Selenium বুকিং প্রক্রিয়া

    চেকার

    হেডলেস Chrome · প্রতিটি ধাপের মাঝে এলোমেলো ১–৩ সেকেন্ড বিরতি

  2. স্লট পাওয়া গেছে → INSERT + NOTIFY

    notification_outbox

    PostgreSQL

    একসঙ্গে সর্বোচ্চ একটি অপেক্ষমাণ APPOINTMENT_FOUND সারি

  3. LISTEN, অথবা প্রতি ২০ সেকেন্ডে খোঁজ

    SKIP LOCKED দিয়ে সারি নেওয়া

    বট

    কুলডাউনের বাইরে থাকা সাবস্ক্রাইবার বাছাই

  4. প্রত্যেক যোগ্য সাবস্ক্রাইবারকে জানানো

    টেলিগ্রাম

    প্রতিটি ডেলিভারি alert_delivery-তে রেকর্ড · ৩ বার ব্যর্থ → অ্যাডমিন

চিত্র 1 · নোটিফিকেশনের পথ। চেকার আর বটের দেখা হয় শুধু PostgreSQL-এ।
ডায়াগ্রামের বর্ণনা

একটি শিডিউলার Selenium চেকার চালু করে, Docker Compose-এর cron দিয়ে অথবা GitHub Actions দিয়ে। চেকার খালি স্লট পেলে নোটিফিকেশন আউটবক্সে একটি APPOINTMENT_FOUND সারি যোগ করে, যদি আগে থেকে কোনোটি অপেক্ষায় না থাকে, এবং NOTIFY পাঠায়। টেলিগ্রাম বট নোটিফিকেশন পেয়ে অথবা প্রতি ২০ সেকেন্ডে খোঁজ নিয়ে জেগে ওঠে, SKIP LOCKED দিয়ে অপেক্ষমাণ সারি নিজের করে নেয়, এবং কুলডাউনের বাইরে থাকা প্রত্যেক সাবস্ক্রাইবারকে মেসেজ পাঠায়, প্রতিটি ডেলিভারি রেকর্ড করে। তিনবার ব্যর্থ হলে সারিটি ব্যর্থ হিসেবে চিহ্নিত হয় এবং অ্যাডমিনকে জানানো হয়।

  1. /subscribe

    টেলিগ্রাম

    নাম, তারপর একটি ইমেইল ঠিকানা

  2. ডোমেইন ও ধারণক্ষমতা যাচাই

    বট

    শুধু অনুমোদিত ডোমেইন, সক্রিয় সাবস্ক্রিপশন সীমিত

  3. ইমেইলে এককালীন কোড

    Amazon SES

  4. /confirm

    টেলিগ্রাম

    পাঁচ দিনের জন্য সাবস্ক্রাইবড, তারপর নিজে থেকেই মেয়াদ শেষ

চিত্র 2 · সাবস্ক্রিপশনের ধাপ। শুধু অনুমোদিত ডোমেইনের যাচাই করা ঠিকানাই সাবস্ক্রাইব করতে পারে।
ডায়াগ্রামের বর্ণনা

ব্যবহারকারী টেলিগ্রাম বটে /subscribe পাঠিয়ে একটি নাম ও ইমেইল ঠিকানা দেন। বট যাচাই করে ডোমেইনটি অনুমোদিত কি না এবং সাবস্ক্রিপশনের সীমা পূর্ণ হয়েছে কি না, তারপর Amazon SES দিয়ে একটি এককালীন কোড পাঠায়। ব্যবহারকারী কোড নিশ্চিত করলে সাবস্ক্রিপশন পাঁচ দিনের জন্য চালু থাকে।

সিদ্ধান্ত

PostgreSQL-এ একটি ট্রানজ্যাকশনাল আউটবক্স রাখা

চেকার শুধু একটি APPOINTMENT_FOUND সারি যোগ করে (যদি আগে থেকে কোনোটি অপেক্ষায় না থাকে), আর ডেলিভারির দায়িত্ব বটের। একটি প্রসেস ব্যর্থ হলেও অন্যটির কিছু যায় আসে না।

অন্য যা ভাবা হয়েছিল

  • চেকার থেকে সরাসরি টেলিগ্রাম API কল করাবট বন্ধ থাকার সময় বা লুপের মাঝে ক্র্যাশ হলে নোটিফিকেশন হারিয়ে যায় বা দুবার যায়।

সিদ্ধান্ত

LISTEN/NOTIFY দিয়ে বট জাগানো, বিকল্প হিসেবে প্রতি ২০ সেকেন্ডে খোঁজ

NOTIFY-এর কারণে ডেলিভারি প্রায় সঙ্গে সঙ্গে হয়, আর সংযোগ বিচ্ছিন্ন হয়ে কিছু ছুটে গেলে খোঁজের লুপ তা ধরে ফেলে।

অন্য যা ভাবা হয়েছিল

  • Redis বা RabbitMQ-এর মতো মেসেজ ব্রোকারএকটিমাত্র কিউয়ের জন্য আরেকটি সার্ভিস চালাতে হতো, যা PostgreSQL-এই আছে।

সিদ্ধান্ত

SKIP LOCKED দিয়ে সারি নেওয়া এবং প্রতিটি ডেলিভারি রেকর্ড করা

প্রতিটি ডেলিভারি alert_delivery টেবিলে লেখা হয়, তাই আবার চেষ্টা করা সারি আগে জানানো সাবস্ক্রাইবারদের বাদ দেয়। তিনবার ব্যর্থ হলে সারিটি failed হিসেবে চিহ্নিত হয় এবং অ্যাডমিনকে জানানো হয়।

অন্য যা ভাবা হয়েছিল

  • ব্যর্থ হলে পুরো পাঠানোর কাজ আবার করাযাঁরা আগেই নোটিফিকেশন পেয়েছেন, তাঁরা আবার পেতেন।

সিদ্ধান্ত

Selenium দিয়ে আসল ব্রাউজার চালানো

ছবি বন্ধ রাখা হেডলেস Chrome মেমরির ব্যবহার কম রাখে। কোনো ক্লিক আটকে গেলে জাভাস্ক্রিপ্ট ক্লিকের বিকল্প প্রক্রিয়াটি চালু রাখে।

অন্য যা ভাবা হয়েছিল

  • সাধারণ HTTP রিকোয়েস্টে বুকিং প্রক্রিয়া নকল করাপ্রক্রিয়াটি কয়েকটি পেজজুড়ে চলে, নকল করতে হলে এর অবস্থা হাতে হাতে বানাতে হতো।

ফলাফল

41

আসল PostgreSQL ডেটাবেসের বিপরীতে ইউনিট টেস্ট

আউটবক্স থেকে সারি নেওয়া, পুনরায় চেষ্টা, আটকে থাকা সারি উদ্ধার, কুলডাউন, সাবস্ক্রিপশন ও Selenium-এর বিকল্প

≤1

প্রতি কুলডাউনে সাবস্ক্রাইবারপ্রতি নোটিফিকেশন

alert_delivery টেবিল দিয়ে নিশ্চিত করা

30 দিন

পর আউটবক্স ও টেলিমেট্রির সারি মুছে যায়

প্রতি রাতে বট পরিষ্কার করে

ভার্সন 1.0.0 GitHub-এ প্রকাশিত। এটি হার্টবিট হেলথ চেকসহ Docker Compose-এ চলে, অথবা GitHub Actions-এ নির্ধারিত সময়ে।

এখন হলে যা অন্যভাবে করতাম

  • বুকিং প্রক্রিয়া ভেঙে গেলে সেটিকে আলাদা নোটিফিকেশন হিসেবে ধরতাম। সিলেক্টর টার্গেট পেজের ওপর নির্ভর করে, আর লেআউটের নীরব পরিবর্তন যেন কখনো "আজ কোনো অ্যাপয়েন্টমেন্ট নেই"-এর মতো না দেখায়।
  • নোটিফিকেশন পৌঁছানোর সময় মাপতাম, স্লট দেখা দেওয়া থেকে মেসেজ পৌঁছানো পর্যন্ত। সাবস্ক্রাইবারদের কাছে এটাই আসল সংখ্যা।