Social & Communication১১ মিনিট পাঠ

নোটিফিকেশন সিস্টেম ডিজাইন (Design a Notification System)

সঠিক বার্তা, সঠিক ব্যক্তির কাছে, সঠিক সময়ে
scope:বাস্তব জগতের সিস্টেম (Real-World System)difficulty:মাঝারি (Intermediate)

সমস্যাটি বোঝা (Understanding the Problem)

নোটিফিকেশন সব জায়গায় আছে। আপনার ফোন টেক্সট মেসেজে বেজে ওঠে, শিপিং আপডেটে আপনার ইমেইল টুং করে, কোনো সেলের (sale) কথা মনে করিয়ে দিতে পুশ নোটিফিকেশন আসে। এই সবকিছুর পেছনে কাজ করে একটি নোটিফিকেশন সিস্টেম (notification system) — এমন একটি সার্ভিস যা সিদ্ধান্ত নেয় কী পাঠাতে হবে, কাকে পাঠাতে হবে এবং কীভাবে পাঠাতে হবে।

ফাংশনাল রিকোয়ারমেন্ট (ব্যবহারিক প্রয়োজনীয়তা):

  • একাধিক চ্যানেল সাপোর্ট করতে হবে: পুশ নোটিফিকেশন (Push notifications) (iOS/Android), SMS, এবং ইমেইল (Email)
  • ইভেন্ট দ্বারা ট্রিগার হওয়া ("আপনার অর্ডার শিপ বা পাঠানো হয়েছে") অথবা শিডিউল করা ("সাপ্তাহিক ডাইজেস্ট")।
  • ব্যবহারকারীরা তাদের প্রেফারেন্স (preference) বা পছন্দ ম্যানেজ করতে পারবেন — যেমন মার্কেটিং ইমেইল বন্ধ করা, সাইলেন্ট বা কোয়ায়েট আওয়ার (quiet hours) বেছে নেওয়া ইত্যাদি।
  • পার্সোনালাইজেশনসহ (ব্যক্তিগতকরণ) টেমপ্লেট সাপোর্ট করা ("হ্যালো {name}, আপনার অর্ডার #{order_id} শিপ করা হয়েছে")।

নন-ফাংশনাল রিকোয়ারমেন্ট (অ-ব্যবহারিক প্রয়োজনীয়তা):

  • রিলায়্যাবিলিটি (Reliability - নির্ভরযোগ্যতা): ক্রিটিকাল বা খুব গুরুত্বপূর্ণ নোটিফিকেশন (পাসওয়ার্ড রিসেট, 2FA কোড) কোনোভাবেই হারানো যাবে না।
  • অন্তত একবার ডেলিভারি (At-least-once delivery): একেবারেই না পাঠানোর চেয়ে দুইবার পাঠানো ভালো (বেশিরভাগ নোটিফিকেশনের ক্ষেত্রে)।
  • স্কেল (Scale): সব চ্যানেল মিলিয়ে প্রতিদিন ১০ মিলিয়নের (10M+) বেশি নোটিফিকেশন।
  • লো ল্যাটেন্সি (Low latency - কম বিলম্ব): সময়-সংবেদনশীল নোটিফিকেশন (যেমন 2FA কোড) কয়েক সেকেন্ডের মধ্যে পৌঁছানো উচিত।
নোটিফিকেশনের ধরন: পুশ, ইমেইল এবং SMS

নোটিফিকেশনের ধরন (Notification Types)

প্রতিটি চ্যানেলের নিজস্ব ডেলিভারি মেকানিজম এবং সীমাবদ্ধতা রয়েছে:

পুশ নোটিফিকেশন (মোবাইল)

  • iOS-এর জন্য APNs (Apple Push Notification service) এবং Android-এর জন্য FCM (Firebase Cloud Messaging)-এর মাধ্যমে ডেলিভার করা হয়।
  • ডিভাইস টোকেনের সাথে প্রোভাইডার বা সরবরাহকারীর কাছে একটি পেলোড (payload - শিরোনাম, বডি, ডেটা) পাঠাতে হয়।
  • প্রোভাইডার এটি ডিভাইসে ডেলিভার করে। টাইমিংয়ের ওপর আপনার কোনো নিয়ন্ত্রণ থাকে না — নোটিফিকেশন কখন দেখাবে তা সম্পূর্ণ OS বা অপারেটিং সিস্টেমের ওপর নির্ভর করে।
  • ডিভাইস টোকেনগুলো ইনভ্যালিড বা বাতিল হয়ে যেতে পারে (যদি ব্যবহারকারী অ্যাপ আনইনস্টল করে বা নতুন ফোন কেনে)।

SMS

  • Twilio, Vonage, অথবা AWS SNS-এর মতো প্রোভাইডারের মাধ্যমে পাঠানো হয়।
  • এটি বেশ ব্যয়বহুল — প্রতি মেসেজে $০.০১-$০.০৫ (বা বেশ কিছু টাকা) খরচ হতে পারে। তাই খুবই কম বা বুঝেশুনে ব্যবহার করতে হয়।
  • গুরুত্বপূর্ণ অ্যালার্টের (2FA কোড, জালিয়াতির সতর্কতা বা fraud alerts) জন্য এটি দারুণ, কারণ প্রায় সবার কাছেই ফোন থাকে।
  • ক্যারেক্টারের বা অক্ষরের সীমাবদ্ধতা থাকে (সাধারণ SMS-এর জন্য ১৬০টি অক্ষর)।

ইমেইল (Email)

  • SendGrid, Amazon SES, অথবা Mailgun-এর মতো প্রোভাইডারের মাধ্যমে পাঠানো হয়।
  • খুব সাশ্রয়ী এবং আকর্ষণীয় — আপনি এতে খুব সহজেই HTML, ছবি, লিংক, বা কোনো ফাইল (অ্যাটাচমেন্ট) যুক্ত করতে পারেন।
  • কিন্তু ডেলিভারি করাটা বেশ চ্যালেঞ্জের: এর কারণ, স্প্যাম ফিল্টার, বাউন্স রেট (পাঠাতে গিয়ে ফিরে আসা), এবং প্রোভাইডারদের থেকে আরোপ করা রেট লিমিট।
  • গুরুত্বপূর্ণ নয় এমন সামগ্রী বা কনটেন্ট-সমৃদ্ধ নোটিফিকেশন (যেমন: অর্ডার সামারি, নিউজলেটার বা খবর)-এর জন্য ইমেইল সবচেয়ে ভালো বিকল্প।

হাই-লেভেল আর্কিটেকচার (High-Level Architecture)

পুরো সিস্টেমটি নিচের মতো করে ভাগ করা যায়:

১. নোটিফিকেশন ট্রিগার (Notification Triggers) — ইভেন্টের উৎস। এটি হতে পারে:

  • একটি ইন্টারনাল বা অভ্যন্তরীণ সার্ভিস ("অর্ডার সার্ভিস বলছে যে অর্ডার #১২৩ পাঠানো হয়েছে")
  • একটি ক্রন জব (Cron job) ("প্রতি সোমবার সাপ্তাহিক ডাইজেস্ট বা সামারি পাঠাও")
  • ব্যবহারকারীর কোনো কাজ বা অ্যাকশন ("আনিকা একটি মন্তব্যে আপনাকে মেনশন করেছে")

২. নোটিফিকেশন সার্ভিস (API) — নোটিফিকেশনের রিকোয়েস্ট গ্রহণ করে, সেগুলো ভ্যালিড বা যাচাই করে, ব্যবহারকারীর পছন্দ বা প্রেফারেন্স দেখে, রেট লিমিট বা মাত্রা প্রয়োগ করে এবং পরিশেষে নোটিফিকেশনটিকে একটি সারিতে (queue) জমা করে।

৩. ইউজার প্রেফারেন্স স্টোর (User Preferences Store) — একটি ডাটাবেস (বা ক্যাশ) যেখানে প্রতিটি ব্যবহারকারীর নোটিফিকেশন সেটিংস সেভ করা থাকে: তারা কোন চ্যানেল চালু রেখেছে, তাদের চুপ থাকার বা সাইলেন্ট থাকার সময় কখন, এবং কতবার নোটিফিকেশন পেতে চায়।

৪. টেমপ্লেট ইঞ্জিন (Template Engine) — এটি ব্যবহারকারীর ব্যক্তিগত ডেটা দিয়ে আগে থেকে তৈরি করা টেমপ্লেটগুলোকে রেন্ডার করে। টেমপ্লেট: "হ্যালো {name}, আপনার অর্ডার #{order_id} রাস্তায় আছে!" → "হ্যালো আনিকা, আপনার অর্ডার #৭৮৯২ রাস্তায় আছে!"

৫. মেসেজ কিউ (Message Queues) — প্রতিটি চ্যানেলের জন্য আলাদা আলাদা কিউ (পুশ কিউ, SMS কিউ, ইমেইল কিউ)। এটি নোটিফিকেশন সার্ভিসটিকে ডেলিভারি থেকে আলাদা (decouple) করে রাখে এবং স্বাধীনভাবে স্কেল করার (scaling) সুযোগ দেয়।

৬. চ্যানেল ওয়ার্কার (Channel Workers) — এগুলো হলো কনজ্যুমার (consumers) যারা কিউ বা সারি থেকে ডেটা টেনে নেয় এবং উপযুক্ত প্রোভাইডারের (যেমন APNs, Twilio, SendGrid) মাধ্যমে সেগুলো ডেলিভারি করে।

৭. ডেলিভারি লগ (Delivery Log) — এটি প্রতিটি নোটিফিকেশন পাঠানোর চেষ্টা এবং তার ফলাফল (পৌঁছেছে, ফিরে এসেছে, বা ব্যর্থ হয়েছে) রেকর্ড করে। এটি অ্যানালিটিক্স, ডিবাগিং এবং পুনরায় চেষ্টা করার (retry logic) জন্য ব্যবহার করা হয়।

পাইপলাইন: ট্রিগার (Trigger) → প্রসেস (Process) → ডেলিভার (Deliver)
Click chart to zoom
নোটিফিকেশন পাঠানো বা পার করার প্রবাহ: ইভেন্ট ট্রিগারের পর প্রেফারেন্স চেক করা হয়, এরপর প্যারালাল বা সমান্তরালভাবে চালু থাকা চ্যানেলগুলোতে রাউট করা হয়

নোটিফিকেশন সার্ভিস কোর লজিক (Notification Service Core Logic)

from dataclasses import dataclass
from enum import Enum
from typing import Optional
import json
class Channel(Enum):
PUSH = "push"
SMS = "sms"
EMAIL = "email"
@dataclass
class NotificationRequest:
user_id: str
template_id: str
channel: Channel
data: dict # Template variables: {name: "Anika", order_id: "7892"}
priority: str = "normal" # "critical", "normal", "low"
class NotificationService:
def __init__(self, preference_store, template_engine,
rate_limiter, queue_client, dedup_cache):
self.preferences = preference_store
self.templates = template_engine
self.rate_limiter = rate_limiter
self.queue = queue_client
self.dedup = dedup_cache
def send(self, request: NotificationRequest) -> dict:
# Step 1: Deduplicate — prevent sending the same notification twice
dedup_key = f"{request.user_id}:{request.template_id}:{hash(str(request.data))}"
if self.dedup.exists(dedup_key):
return {"status": "skipped", "reason": "duplicate"}
# Step 2: Check user preferences
prefs = self.preferences.get(request.user_id)
if not prefs.is_channel_enabled(request.channel):
return {"status": "skipped", "reason": "user_opted_out"}
if prefs.is_quiet_hours():
if request.priority != "critical": # Critical notifications bypass quiet hours
return {"status": "deferred", "reason": "quiet_hours"}
# Step 3: Rate limit — don't spam users
if not self.rate_limiter.allow(request.user_id, request.channel):
return {"status": "rate_limited"}
# Step 4: Render template
content = self.templates.render(request.template_id, request.data)
# Step 5: Enqueue to the correct channel queue
message = {
"user_id": request.user_id,
"channel": request.channel.value,
"content": content,
"priority": request.priority,
"attempt": 1
}
queue_name = f"notifications-{request.channel.value}"
self.queue.publish(queue_name, json.dumps(message))
# Step 6: Mark as sent for deduplication
self.dedup.set(dedup_key, ttl=3600)
return {"status": "queued", "channel": request.channel.value}
# Usage
# service.send(NotificationRequest(
# user_id="user_42",
# template_id="order_shipped",
# channel=Channel.PUSH,
# data={"name": "Anika", "order_id": "7892"}
# ))
Output
# Returns: {"status": "queued", "channel": "push"}
# Message flow: API → Queue → Push Worker → APNs → User's phone

রিলায়্যাবিলিটি এবং রিট্রাই লজিক (Reliability and Retry Logic)

নোটিফিকেশন নানা কারণে ব্যর্থ হতে পারে: ব্যবহারকারীর ফোন বন্ধ থাকতে পারে, ইমেইল বাউন্স করতে পারে, বা SMS প্রোভাইডারের সার্ভার ডাউন থাকতে পারে। একটি নির্ভরযোগ্য সিস্টেম এই সমস্ত ব্যর্থতাকে খুব ভালোভাবে (gracefully) সামলে নেয়।

এক্সপোনেনশিয়াল ব্যাকঅফ (exponential backoff)-এর সাথে রিট্রাই বা পুনরায় চেষ্টা: ডেলিভারি ব্যর্থ হলে, ১ সেকেন্ড পর, তারপর ৪ সেকেন্ড, তারপর ১৬ সেকেন্ড, এরপর ৬৪ সেকেন্ড পর পুনরায় চেষ্টা করা হয়। এটি কোনো সমস্যাগ্রস্ত প্রোভাইডারকে অনবরত বা ঘনঘন রিকোয়েস্ট করে আরো বিপদে ফেলা থেকে বিরত রাখে।

সর্বোচ্চ রিট্রাই (Max retries): N সংখ্যকবার (যেমন, ৫ বার) ব্যর্থ হওয়ার পর, ম্যানুয়াল ইনভেস্টিগেশন বা তদন্তের জন্য নোটিফিকেশনটিকে একটি ডেড লেটার কিউ (dead letter queue)-তে সরিয়ে রাখা হয়। চিরকাল ধরে চেষ্টা করা হয় না।

ইডিমপোটেন্সি (Idempotency): রিট্রাই করার কারণে কখনো কখনো ভুলে একই নোটিফিকেশন দুইবার ডেলিভার হতে পারে। গুরুত্বপূর্ণ নয় এমন নোটিফিকেশনের ক্ষেত্রে ("কেউ আপনার পোস্টে লাইক দিয়েছে") এটি বিরক্তিকর হলেও মেনে নেয়া যায়। তবে ক্রিটিকাল নোটিফিকেশনের ক্ষেত্রে ("আপনার 2FA কোড হলো ১২৩৪৫৬"), নোটিফিকেশন আইডি ব্যবহার করে ক্লায়েন্ট-সাইডে ডিডুপ্লিকেট বা নকল চেক করতে হয়।

ফলব্যাক চ্যানেল (Fallback channels): পুশ নোটিফিকেশন যদি কোনো কারণে ব্যর্থ হয় (হতে পারে ব্যবহারকারী অ্যাপটি আনইনস্টল করে দিয়েছেন), সেক্ষেত্রে SMS বা ইমেইলের মাধ্যমে পাঠানোর ব্যবস্থা করা হয় (ফলব্যাক বা fallback)। একটি প্রায়োরিটি চেইন (Priority chain) নির্ধারণ করে দিন, যেমন: পুশ (Push) → SMS → ইমেইল (Email)।

ইউজার প্রেফারেন্স: চ্যানেল ফিল্টার করা
এক্সপোনেনশিয়াল ব্যাকঅফ (exponential backoff) এর মাধ্যমে রিট্রাই (Retry) এবং রিলায়্যাবিলিটি

ইউজার প্রেফারেন্স এবং রেট লিমিটিং (Rate Limiting)

কেউ স্প্যাম (spam) বা বিরক্ত হতে পছন্দ করে না। একটি ভালো নোটিফিকেশন সিস্টেম ব্যবহারকারীর পছন্দকে সম্মান করে:

  • চ্যানেল অপ্ট-ইন/অপ্ট-আউট (Channel opt-in/opt-out): "আমাকে পুশ নোটিফিকেশন পাঠান কিন্তু ইমেইল নয়।"
  • ক্যাটাগরি প্রেফারেন্স: "আমি অর্ডার আপডেট পেতে চাই কিন্তু কোনো মার্কেটিং অফার নয়।"
  • কোয়ায়েট আওয়ার্স (Quiet hours - চুপ থাকার সময়): "রাত ১০টা থেকে সকাল ৮টার মধ্যে আমাকে বিরক্ত করবেন না" (নিরাপত্তা বা ক্রিটিকাল অ্যালার্ট ছাড়া)।
  • ফ্রিকোয়েন্সি ক্যাপস (Frequency caps - সংখ্যার সীমা): "প্রতি ঘণ্টায় ৫টির বেশি নোটিফিকেশন নয়।" এটি হঠাৎ অনেক অ্যাক্টিভিটির কারণে (যেমন কোনো জনপ্রিয় পোস্টে ৫০টি লাইক) কারোর ফোন ৫০ বার বাজতে বাধা দেয়।

প্রতি ব্যবহারকারীর জন্য নোটিফিকেশনের রেট লিমিট করা মূলত API রেট লিমিটিং থেকে আলাদা বা ভিন্ন। এখানে আপনি সার্ভারকে নয়, বরং ইউজারের এক্সপেরিয়েন্স বা অভিজ্ঞতাকে সুরক্ষিত করছেন। সম্ভব হলে নোটিফিকেশনগুলোকে অ্যাগ্রিগেট (Aggregate) বা একত্রিত করুন: ৪৮টি আলাদা নোটিফিকেশনের বদলে "আনিকা এবং আরও ৪৭ জন আপনার পোস্টে লাইক দিয়েছে" দেখান।

Note: একটি নোটিফিকেশন সিস্টেমকে ডাক বিভাগের বা পোস্টাল সার্ভিসের (postal service) মতো ভাবতে পারেন। নোটিফিকেশন সার্ভিসটি হলো পোস্ট অফিস — এটি মেইল বা চিঠি সর্ট (sort) করে বা বাছাই করে। মেসেজ কিউগুলো হলো ডেলিভারি ট্রাক বা বাহন — একটি প্যাকেজের জন্য (পুশ), একটি চিঠির জন্য (ইমেইল), একটি টেলিগ্রামের জন্য (SMS)। ইউজার প্রেফারেন্সগুলো হলো মেইলবক্সের গায়ে লাগানো "কোনো জং মেইল নয়" (No Junk Mail) সাইনবোর্ড। এবং রিট্রাই লজিক হলো 'প্রেরকের কাছে ফেরত দিন, আগামীকাল আবার চেষ্টা করুন' (return to sender, try again tomorrow) প্রক্রিয়া।
পূর্ণাঙ্গ আর্কিটেকচার: স্কেল করা যায় এমন মাল্টি-চ্যানেল সিস্টেম

অ্যানালিটিক্স এবং ট্র্যাকিং (Analytics and Tracking)

নোটিফিকেশনগুলো আসলেই কাজ করছে কিনা তা জানা অত্যন্ত জরুরি। নিচের মেট্রিক বা স্ট্যাটগুলো ট্র্যাক করুন:

  • ডেলিভারি রেট (Delivery rate): নোটিফিকেশনের কত শতাংশ ব্যবহারকারীর কাছে আসলেই পৌঁছেছে? (APNs এবং FCM ডেলিভারি রিসিট প্রদান করে।)
  • ওপেন রেট (Open rate): কত শতাংশ পুশ নোটিফিকেশন ট্যাপ করা হয়েছে? কত শতাংশ ইমেইল খোলা হয়েছে? (ইমেইলের জন্য ট্র্যাকিং পিক্সেল বা tracking pixels ব্যবহার করুন।)
  • ক্লিক-থ্রু রেট (Click-through rate): কতজন ব্যবহারকারী নোটিফিকেশনের লিংকে ক্লিক করেছেন?
  • আনসাবস্ক্রাইব রেট (Unsubscribe rate): নোটিফিকেশনের কারণে কি ব্যবহারকারীরা অপ্ট আউট (opt out) বা আনসাবস্ক্রাইব করছেন? আনসাবস্ক্রাইবের হার বেশি হলে বুঝতে হবে আপনি প্রয়োজনের চেয়ে বেশি মেসেজ বা স্প্যাম পাঠাচ্ছেন।
  • ল্যাটেন্সি (Latency - বিলম্ব): ট্রিগার থেকে শুরু করে ডেলিভারি পর্যন্ত লাগা সময়। 2FA কোডের মতো সময়-সংবেদনশীল অ্যালার্টের জন্য এটি অত্যন্ত গুরুত্বপূর্ণ।

অ্যানালিটিক্সের জন্য একটি ডাটা ওয়্যারহাউসে (data warehouse - যেমন BigQuery বা Snowflake) ডেলিভারি ইভেন্টগুলো স্টোর বা সংরক্ষণ করুন। রিয়েল-টাইমে সিস্টেমের হেলথ (health) বা সুস্থতা নিরীক্ষণের জন্য ড্যাশবোর্ড (dashboards) ব্যবহার করুন।

Note: ইন্টারভিউ টিপস: একটি নোটিফিকেশন সিস্টেম ডিজাইনে ইন্টারভিউয়াররা প্রধানত ৩টি জিনিস খোঁজেন: (১) প্রতিটি চ্যানেলের জন্য আলাদা কিউ-সহ মাল্টি-চ্যানেল সাপোর্ট, (২) স্প্যাম রোধ করার জন্য ইউজার প্রেফারেন্স এবং রেট লিমিটিং, এবং (৩) রিলায়্যাবিলিটি — রিট্রাই লজিক, ডেড লেটার কিউ, এবং ফলব্যাক চ্যানেল। এই তিনটি বিষয় অন্তর্ভুক্ত করতে পারলে আপনার ডিজাইনটি দারুণ হবে।

Key Metrics

নোটিফিকেশন API → Queue-তে দেওয়া
খুব দ্রুত এনকিউ (enqueue) করা যায়
~৫-২০ ms \(O(1)\)
পুশ ডেলিভারি (APNs/FCM)
প্রোভাইডার ল্যাটেন্সি
~১০০-৫০০ ms \(O(1)\)
SMS ডেলিভারি (Twilio)
ক্যারিয়ার রাউটিং (Carrier routing)
~১-৫ sec (সেকেন্ড) \(O(1)\)
ইমেইল ডেলিভারি (SES)
SMTP হ্যান্ডশেক + ডেলিভারি
~১-৩০ sec (সেকেন্ড) \(O(1)\)
টেমপ্লেট রেন্ডারিং
n = টেমপ্লেটের আকার
~১-৫ ms \(O(n)\)
প্রেফারেন্স লুকআপ (cache করা)
রেডিজ ক্যাশ (Redis cache)
< ১ ms \(O(1)\)
দৈনন্দিন থ্রুপুট টার্গেট
~গড়ে ১১৫টি/sec
১০ মিলিয়ন+ (10M+) নোটিফিকেশন/দিন —

ছোট কুইজ

কেন প্রতিটি নোটিফিকেশন চ্যানেলের (পুশ, SMS, ইমেইল) জন্য আলাদা আলাদা মেসেজ কিউ (message queues) ব্যবহার করা উচিত?

পড়া চালিয়ে যান