পাঠ ৪০ · ৫৭-এর মধ্যে · মডিউল ৯
Home / Courses / Mobile App Development / পুশ ও WebSocket

মোবাইলে রিয়েল-টাইম আপডেট — পুশ ও WebSocket

Real-time updates on mobile — push and WebSocket
৯ মিনিট পড়া মধ্যম · Intermediate Python কোডসহ সম্পূর্ণ বাংলায়

এই পাঠে যা শিখবেন

  • পুশ নোটিফিকেশন ও WebSocket-এর মধ্যে মৌলিক আর্কিটেকচারাল পার্থক্য — কে ডেলিভারির দায়িত্ব নেয়
  • কেন killed স্টেটে শুধু পুশ কাজ করে, WebSocket করে না
  • একটি সত্যিকারের সিমুলেশন যা সব লাইফসাইকেল স্টেটের বিপরীতে উভয় পদ্ধতির প্রকৃত আচরণ দেখায়

১ · দুটি ভিন্ন আর্কিটেকচার

একটি মোবাইল অ্যাপে "রিয়েল-টাইম" আপডেট আনার দুটি মৌলিকভাবে ভিন্ন উপায় আছে। পুশ নোটিফিকেশন OS-এর নিজস্ব পুশ সার্ভিসের (প্রতিটি প্ল্যাটফর্মের নিজস্ব একটি কেন্দ্রীয় সিস্টেম প্রসেস) মাধ্যমে আসে — সার্ভার সেই OS-সার্ভিসকে পেলোড পাঠায়, আর OS-ই ডিভাইসে ডেলিভার করে, প্রয়োজনে অ্যাপকে সংক্ষিপ্তভাবে জাগিয়ে তুলে। WebSocket বা অন্য কোনো ইন-অ্যাপ দীর্ঘস্থায়ী সংযোগ সম্পূর্ণ ভিন্ন — এটি অ্যাপের নিজস্ব প্রসেসের ভেতরে চলা একটি সরাসরি TCP সংযোগ। অ্যাপ প্রসেস বন্ধ হলে এই সংযোগও তার সাথেই মারা যায়।

পুশ নোটিফিকেশন
OS-এর কেন্দ্রীয় পুশ সার্ভিস ডেলিভারির দায়িত্ব নেয় — অ্যাপ প্রসেস চলুক বা না চলুক।
WebSocket
অ্যাপের নিজস্ব প্রসেসের ভেতরে চলা সংযোগ — অ্যাপ killed হলে সংযোগও killed।
killed স্টেট
একমাত্র এই স্টেটেই দুটি পদ্ধতির আচরণ আলাদা হয়ে যায় — বাকি সব স্টেটে উভয়ই কাজ করতে পারে।

২ · সব লাইফসাইকেল স্টেটের বিপরীতে ডেলিভারি সিমুলেশন

নিচের কোডে L01/L37-এর AppLifecycle ধাঁচ পুনর্ব্যবহার করে foreground, background, ও killed — এই তিনটি স্টেটের বিপরীতে একটি পুশ ডেলিভারি ও একটি WebSocket-মেসেজ ডেলিভারি চেষ্টা করা হয়েছে।

Python
# পুশ বনাম WebSocket ডেলিভারি -- সব AppLifecycle স্টেটের বিপরীতে পরীক্ষা

class AppLifecycle:
    ALLOWED = {
        'not_running': {'foreground'},
        'foreground':  {'background'},
        'background':  {'foreground', 'killed'},
        'killed':      set(),
    }

    def __init__(self, state='foreground'):
        self.state = state


def deliver_push(app_state, payload):
    # OS-এর নিজস্ব পুশ সার্ভিস ডেলিভার করে -- অ্যাপ প্রসেস killed থাকলেও এটি ডেলিভার হতে পারে
    return {
        "delivered": True,
        "via": "OS push service",
        "app_state": app_state,
        "payload": payload,
    }


def deliver_websocket_message(app_state, payload, undelivered_queue):
    # অ্যাপের নিজস্ব প্রসেসের ভেতরে চলা সংযোগ -- killed অবস্থায় সংযোগও বেঁচে থাকে না
    if app_state in ("foreground", "background"):
        return {
            "delivered": True,
            "via": "in-app WebSocket",
            "app_state": app_state,
            "payload": payload,
        }
    undelivered_queue.append(payload)
    return {
        "delivered": False,
        "via": "in-app WebSocket",
        "app_state": app_state,
        "reason": "সংযোগ killed অবস্থায় বেঁচে থাকে না -- মেসেজ ডেলিভার করা যায়নি",
    }


states_to_test = ["foreground", "background", "killed"]
undelivered_queue = []

print("-- পুশ নোটিফিকেশন ডেলিভারি --")
for state in states_to_test:
    result = deliver_push(state, "নতুন মেসেজ এসেছে")
    print(f"state={state:10s} -> delivered={result['delivered']}  via={result['via']}")

print("\n-- WebSocket মেসেজ ডেলিভারি --")
for state in states_to_test:
    result = deliver_websocket_message(state, f"চ্যাট আপডেট ({state})", undelivered_queue)
    print(f"state={state:10s} -> delivered={result['delivered']}  via={result['via']}")

print(f"\nkilled অবস্থায় ডেলিভার না হয়ে জমে থাকা WebSocket মেসেজ: {undelivered_queue}")

    
লক্ষ্য করুন deliver_push()-এর ফলাফল তিনটি স্টেটেই delivered=True — এমনকি killed-এও, কারণ পুশ ডেলিভারি অ্যাপের প্রসেসের ওপর নির্ভর করে না। কিন্তু deliver_websocket_message()-এর ফলাফল foreground ও background-এ True, অথচ killed-এ False — মেসেজটি undelivered_queue-তে জমা থাকে, ঠিক যেমন বাস্তবে সার্ভার-সাইড সিস্টেম প্রায়ই ডেলিভার-না-হওয়া মেসেজ পরে পুশ হিসেবে পাঠানোর জন্য সংরক্ষণ করে রাখে।
মূল কথা · Key takeaway

একটি নির্ভরযোগ্য রিয়েল-টাইম মোবাইল ফিচার প্রায়ই দুটি পদ্ধতিই একসাথে ব্যবহার করে — অ্যাপ ফোরগ্রাউন্ডে থাকলে দ্রুত, রিচ WebSocket আপডেট, আর অ্যাপ ব্যাকগ্রাউন্ড/killed অবস্থায় থাকলে একটি পুশ নোটিফিকেশন ফলব্যাক হিসেবে ব্যবহারকারীকে জানায় "নতুন কিছু এসেছে, অ্যাপ খুলুন"। L45-এ (M10) আমরা পুশ নোটিফিকেশনের পূর্ণ pub-sub ডেলিভারি প্যাটার্ন গড়ে তুলব।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।

প্র ০১ একটি পুশ নোটিফিকেশন যদি অ্যাপ killed অবস্থায় থাকতেই ডেলিভার হতে পারে, তাহলে সব ডেটা পুশের মাধ্যমেই কেন পাঠানো হয় না, WebSocket আদৌ কেন দরকার?

পুশ নোটিফিকেশন সাধারণত ছোট, সংক্ষিপ্ত পেলোডের জন্য উপযুক্ত (একটি বার্তা, একটি সংখ্যা) এবং প্রতিটি পুশে কিছুটা বিলম্ব ও ওভারহেড থাকে — উচ্চ-ফ্রিকোয়েন্সি, বড়, ধারাবাহিক ডেটা (যেমন লাইভ চ্যাট টাইপিং ইন্ডিকেটর, রিয়েল-টাইম গেম স্টেট) এর জন্য অনুপযুক্ত। WebSocket যখন অ্যাপ সক্রিয়ভাবে ব্যবহৃত হচ্ছে তখন অনেক দ্রুত ও কম-ওভারহেড যোগাযোগের সুযোগ দেয়, যা পুশ দিতে পারে না।

প্র ০২ উপরের কোডে background স্টেটে WebSocket ডেলিভারি True দেখানো হয়েছে — এটি কি বাস্তবসম্মত?

আংশিকভাবে — বাস্তবে background স্টেটে OS একটি সীমিত গ্রেস পিরিয়ড দেয় (ঠিক যেমন L37-এ দেখা হয়েছে), যার মধ্যে সংযোগ কিছু সময়ের জন্য বেঁচে থাকতে পারে, কিন্তু চিরকাল নয়। এই পাঠের সিমুলেশন সরলীকৃত — background-কে "এখনও বেঁচে আছে" হিসেবে দেখানো হয়েছে, কিন্তু একটি সম্পূর্ণ মডেলে L37-এর গ্রেস-পিরিয়ড লজিকও এখানে যুক্ত করা যেত।

প্র ০৩ একটি ওয়েব পেজে সমতুল্য কোনো ধারণা কি আছে যা মোবাইলের পুশ নোটিফিকেশনের মতো, ট্যাব বন্ধ থাকলেও কাজ করে?

হ্যাঁ — ব্রাউজারের Web Push API/Service Worker-ভিত্তিক নোটিফিকেশন কিছুটা একই ধারণা অনুসরণ করে: ব্রাউজারের নিজস্ব ব্যাকগ্রাউন্ড সার্ভিস ওয়ার্কার ট্যাব বন্ধ থাকলেও নোটিফিকেশন দেখাতে পারে। তবে এর পরিধি মোবাইল OS-পুশের চেয়ে সীমিত — এটি নির্ভর করে ব্রাউজার নিজেই চলমান থাকা এবং ব্যবহারকারী অনুমতি দেওয়ার ওপর, যেখানে মোবাইল OS-পুশ পুরো অপারেটিং সিস্টেম স্তরে কাজ করে।

অনুশীলন

  1. চিন্তা করুন: একটি লাইভ ক্রিকেট স্কোর অ্যাপের কথা ভাবুন — কোন আপডেট পুশের মাধ্যমে পাঠানো উচিত, আর কোনটি WebSocket-এর মাধ্যমে, এবং কেন?

    গুরুত্বপূর্ণ মাইলফলক (উইকেট পড়া, ইনিংস শেষ) পুশের মাধ্যমে পাঠানো ভালো, কারণ ব্যবহারকারী তখন অ্যাপ খোলা নাও রাখতে পারেন এবং এই ইভেন্টগুলো কম-ফ্রিকোয়েন্সি। কিন্তু বল-বাই-বল স্কোর আপডেট, যা ব্যবহারকারী সক্রিয়ভাবে অ্যাপ খুলে দেখছেন, WebSocket-এর মাধ্যমে দেওয়া ভালো — উচ্চ-ফ্রিকোয়েন্সি, প্রতিটির জন্য আলাদা নোটিফিকেশন পাঠানো অবাস্তব ও বিরক্তিকর হবে।

  2. পরীক্ষা করুন: উপরের কোড সেলে states_to_test তালিকায় "not_running" যোগ করুন এবং কোডটি আবার চালিয়ে দেখুন উভয় ডেলিভারি ফাংশন এই স্টেটে কী ফলাফল দেয়।

    deliver_push("not_running", ...) এখনও delivered=True দেবে, কারণ এই ফাংশনের লজিক কোনো স্টেটকে বিশেষভাবে ব্যতিক্রম হিসেবে ধরে না — শুধু ফলাফল রিটার্ন করে। কিন্তু deliver_websocket_message("not_running", ...)-এর জন্য if app_state in ("foreground", "background") শর্ত মিথ্যা হওয়ায় এটিও killed-এর মতোই delivered=False দেবে এবং মেসেজ কিউতে জমা হবে — যা যৌক্তিক, কারণ অ্যাপ এখনো চালুই হয়নি, তার কোনো সক্রিয় সংযোগ থাকতে পারে না।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

আগের পাঠ
ব্যাকগ্রাউন্ড সিঙ্ক ও ফেচ