এই ব্লগ পোস্টে, আমরা আপনার ওয়েবসাইটের জন্য একটি ওয়েইটিং রুম পেজ ইমপ্লিমেন্ট করব।
কেন? 🤔
ওয়েবসাইটে বেশি ভিজিটর আসা সাধারণত ভালো ব্যাপার কিন্তু সবসময় নয়। অকস্মিক হাই ট্রাফিক সহজেই আপনার অ্যাপ্লিকেশনকে অভিভূত করে দিতে পারে যা আপনার সার্ভিসগুলো সম্পূর্ণরূপে ব্যাহত করতে পারে। ওয়েইটিং রুম হলো একটি সমাধান যা আপনাকে ট্রাফিক নিয়ন্ত্রণ করতে এবং ট্রাফিক সার্জের সময় আপনার রিসোর্স প্রোটেক্ট করতে সাহায্য করে। Cloudflare Waiting Room একটি ভালো সমাধান কিন্তু এটি শুধু বিজনেস এবং এন্টারপ্রাইজ অ্যাকাউন্টের জন্য উপলব্ধ। চিন্তা নয়, এই ব্লগে আমরা ক্লাউডফ্লেয়ার ওয়ার্কার্স এবং আপস্ট্যাশ রেডিস ব্যবহার করে যেকোনো টাইপের ওয়েবসাইটের জন্য একটি ওয়েইটিং রুম বানাব।
কীভাবে? ⚙️
ওয়েইটিং রুম নিয়ন্ত্রণের জন্য দুটি প্যারামিটার আছে।
- ম্যাক্স সেশন ডিউরেশন: একজন ভিজিটর ওয়েবসাইটে কতক্ষণ আইডল থাকতে পারে?
- ম্যাক্স ওয়েবসাইট ক্যাপাসিটি: একই সময়ে ওয়েবসাইট কতজন ভিজিটর অনুমতি দিতে পারে?
যখন একজন ভিজিটর আমাদের ওয়েবসাইটে এন্টার করে, আমরা একটি ইউনিক কি (সেশন কির মত) জেনারেট করব এবং সেটি রেডিসে রাখব। আমরা এই কিটি রেডিসে এক্সপাইরেশন টাইম সহ রাখব যা হলো ম্যাক্স সেশন ডিউরেশন। একজন ভিজিটরকে ওয়েবসাইটে ঢুক देने আগে, আমরা রেডিসের dbsize চেক করব। যদি সাইজ ম্যাক্স ওয়েবসাইট ক্যাপাসিটি-র চেয়ে বেশি হয়, তবে আমরা ভিজিটরকে ওয়েইটিং রুমে ফরওয়ার্ড করব। ওয়েইটিং রুম হলো একটি স্ট্যাটিক এইচটিএমএল যা প্রতি ৩০ সেকেন্ডে রিফ্রেশ হয়। অর্থাৎ, প্রতি ৩০ সেকেন্ডে একবার, ভিজিটরকে ওয়েবসাইটে ঢুকতে দেওয়া হবে যদি উপলব্ধতা থাকে।
জেনারেট করা ইউনিক কিটি ভিজিটরের রিকোয়েস্টগুলোর সাথে কুকি হিসেবে লিখা হয়। তাই একই ভিজিটরের রিকোয়েস্টগুলোর একই কি থাকবে। ক্যাপাসিটি ফুল হলে একটি ভিজিটরের রেডিস কীস্পেসে সেশন আছে কিনা চেক করার জন্য এটি জরুরি। তাই একজন ভিজিটর হিসেবে আপনাকে ওয়েবসাইটে ঢুকতে দেওয়া হবে এমনকি ক্যাপাসিটি ফুল থাকলেও যতক্ষণ না আপনার কি রেডিস কীস্পেসে আছে। যদি আপনি ম্যাক্স সেশন ডিউরেশন চেয়ে বেশি সময় আইডল থাকেন, তবে আপনার কি রেডিস থেকে ডিলিট হয়ে যাবে। এবং যদি ক্যাপাসিটি ফুল থাকে যখন আপনি রিকোয়েস্ট পাঠাবেন, আপনাকে ওয়েইটিং রুমে ফরওয়ার্ড করা হবে।
এই লজিকটি আমরা ক্লাউডফ্লেয়ার ওয়ার্কারসে ইমপ্লিমেন্ট করব। আমরা আপস্ট্যাশ ব্যবহার করব রেডিস স্টোর হিসেবে। এখন এই টেকনোলজি ডিসিশনগুলোর ব্যাকগ্রাউন্ড ব্যাখ্যা করি।
কেন ক্লাউডফ্লেয়ার ওয়ার্কার্স? 🌍
ওয়েইটিং রুম ইমপ্লিমেন্টেশন আপনার ওয়েবসাইটের সকল রিকোয়েস্ট ইন্টারসেপ্ট করবে। তাই এর পারফরম্যান্স ওভারহেড মিনিমাল হওয়া উচিত। ক্লাউডফ্লেয়ার ওয়ার্কার্স ক্লাউডফ্লেয়ার এজ ইনফ্রাস্ট্রাকচার লিভারেজ করে, তাই এটি গ্লোবালি মিনিমাম লেটেন্সি দেয়। এডব্লিউএস ল্যাম্বডার মত, এর কোনো কোল্ড স্টার্ট সমস্যা নেই। এটি একটি সার্ভারলেস টেকনোলজি তাই স্কেলেবিলিটিও কোনো সমস্যা নয়।
কেন আপস্ট্যাশ রেডিস? 🚀
প্রতিটি নতুন ভিজিটরের আগে ওয়েবসাইটের করেন্ট সাইজ চেক করতে হবে। ক্লাউডফ্লেয়ার ওয়ার্কার্স স্টেটলেস তাই এই ইনফরমেশন এক্সটার্নালি রাখতে হবে। রেডিস কম লেটেন্সির সাথে সেরা চয়েস। কিন্তু রেডিস অফারিংস টিসিপি-বেসড কানেকশন চায় যা ক্লাউডফ্লেয়ার ওয়ার্কার্সে সাপোর্টেড নয়। আপস্ট্যাশ একমাত্র রেডিস অফারিং যেটি বিল্ট-ইন রেস্ট এপিআই সহ আসে। এছাড়া গ্লোবাল রেপ্লিকেশন 덕분에 এটি সারা বিশ্বে কম লেটেন্সি দেয়।
স্টেপ বাই স্টেপ ইমপ্লিমেন্টেশন 🛠️
নিচে স্টেপ বাই স্টেপ প্রজেক্ট ইমপ্লিমেন্ট করব। যদি আপনি প্রজেক্টটি ক্লোন করে সরাসরি আপনার ওয়েবসাইটের জন্য ওয়েইটিং রুম সেটআপ করতে চান, তবে সোর্স কোড-এর রিডমিতে দেওয়া স্টেপগুলো ফলো করুন।
1 প্রজেক্ট সেটআপ
রংগলার ব্যবহার করে প্রজেক্ট তৈরি করুন।
wrangler generate waiting-room
তারপর ডিপেন্ডেন্সি ইনস্টল করুন:
npm install cookie @upstash/redis
2 wrangler.toml আপডেট করুন
টাইপ আপডেট করুন:
type = "webpack"
আপনার ক্লাউডফ্লেয়ার অ্যাকাউন্ট আইডি সেট করুন। এখানে চেক করুন আপনার অ্যাকাউন্ট আইডি খুঁজে বের করতে।
account_id = "REPLACE_HERE"
এই ভেরিয়েবলগুলো যোগ করুন:
[vars]
UPSTASH_REDIS_REST_TOKEN = "REPLACE_HERE"
UPSTASH_REDIS_REST_URL = "REPLACE_HERE"
TOTAL_ACTIVE_USERS = 10
SESSION_DURATION_SECONDS = 30
আপস্ট্যাশ কনসোল থেকে একটি গ্লোবাল ডেটাবেস তৈরি করুন। আপনাকে কনসোল থেকে রেস্ট টোকেন এবং ইউআরএল কপি-পেস্ট করতে হবে। রেডিস ডেটাবেস początကçekে খালি থাকবে এবং শুধু এই অ্যাপ্লিকেশন দ্বারা ব্যবহার করা হবে।
আপনার নিজস্ব রিকোয়ারমেন্ট অনুযায়ী TOTAL_ACTIVE_USERS এবং SESSION_DURATION_SECONDS সেট করুন।
3 index.js
Index.js হলো ক্লাউডফ্লেয়ার ওয়ার্কার্স ইমপ্লিমেন্টেশন ফাইল। তাই সকল লজিক এখানে রাখব। নিচের কোড কপি-পেস্ট করুন:
import { parse } from "cookie";
import { Redis } from "@upstash/redis/cloudflare";
const redis = Redis.fromEnv();
addEventListener("fetch", (event) => {
event.respondWith(
handleRequest(event.request).catch(
(err) => new Response(err.stack, { status: 500 })
)
);
});
const COOKIE_NAME_ID = "__waiting_room_id";
const COOKIE_NAME_TIME = "__waiting_room_last_update_time";
const init = {
headers: {
Authorization: "Bearer " + UPSTASH_REDIS_REST_TOKEN,
},
};
async function handleRequest(request) {
const { pathname } = new URL(request.url);
if (!pathname.startsWith("/favicon")) {
const cookie = parse(request.headers.get("Cookie") || "");
let userId;
if (cookie[COOKIE_NAME_ID] != null) {
userId = cookie[COOKIE_NAME_ID];
} else {
userId = makeid(8);
}
const size = await redis.dbsize();
console.log("current capacity:" + size);
// there is enough capacity
if (size < TOTAL_ACTIVE_USERS) {
return getDefaultResponse(request, cookie, userId);
} else {
// site capacity is full
const user = await redis.get(userId);
if (user === "1") {
// the user has already active session
return getDefaultResponse(request, cookie, userId);
} else {
// capacity is full so the user is forwarded to waiting room
return getWaitingRoomResponse(userId);
}
}
} else {
return fetch(request);
}
}
async function getDefaultResponse(request, cookie, userId) {
// uncomment below to test the function with a static html content
// const newResponse = new Response(default_html)
// newResponse.headers.append('content-type', 'text/html;charset=UTF-8')
const response = await fetch(request);
const newResponse = new Response(response.body, response);
const now = Date.now();
let lastUpdate = cookie[COOKIE_NAME_TIME];
if (!lastUpdate) lastUpdate = 0;
const diff = now - lastUpdate;
const updateInterval = (SESSION_DURATION_SECONDS * 1000) / 2;
if (diff > updateInterval) {
await redis.setex(userId, SESSION_DURATION_SECONDS, 1);
newResponse.headers.append(
"Set-Cookie",
`${COOKIE_NAME_TIME}=${now}; path=/`
);
}
newResponse.headers.append(
"Set-Cookie",
`${COOKIE_NAME_ID}=${userId}; path=/`
);
return newResponse;
}
async function getWaitingRoomResponse(userId) {
const newResponse = new Response(waiting_room_html);
newResponse.headers.set("content-type", "text/html;charset=UTF-8");
return newResponse;
}
function makeid(length) {
let result = "";
const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
const charactersLength = characters.length;
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
const waiting_room_html = `
Waiting Room
You are now in line.
Thanks for your patience.
We are experiencing a high volume of traffic. Please sit tight and we will let you in soon.
This page will automatically refresh, please do not close your browser.
`;
const default_html = `
Waiting Room Demo
Waiting Room Demo
Visit this site from a different browser, you will be forwarded to the waiting room when the capacity is full.
Check this project to set up a waiting room for your website.
`;
উপরের কোডে, আপনি waiting_room_html ভেরিয়েবলটি এডিট করতে পারেন। এটি ওয়েইটিং রুম পেজের স্ট্যাটিক এইচটিএমএল।
handleRequest মেথড আপনার ওয়েবসাইটের উপলব্ধতার উপর ভিত্তি করে getDefaultResponse বা getWaitingRoomResponse রিটার্ন করে।
4 লোকালি রান করুন
ওয়েইটিং রুম লোকালি টেস্ট করতে, ক্যাপাসিটি ১ এবং সেশন ডিউরেশন ৩০ সেকেন্ড সেট করা বুঝদার। তারপর রান করুন:
wrangler dev
এখন https://127.0.0.1:8787/ ক্রোমে খুলুন, আপনি দেখবেন:

এবং তারপর সেম ইউআরএল সাফারি-তে (অথবা ক্রোম ইन्कগনিটো) খুলুন, আপনি দেখবেন:

৩০ সেকেন্ডের বেশি অপেক্ষা করুন। আপনি দেখবেন ওয়েইটিং রুমের পেজ রিফ্রেশ হয়ে ওয়েবসাইটে এন্টার করছে।
আমাদের লোকাল একটি রিয়েল ওয়েবসাইটে ফরওয়ার্ড করে না তাই ক্লাউডফ্লেয়ার-এর ৪০৪ পেজ দেখাচ্ছে, এটা ঠিক আছে।
5 পাবলিশ করুন
আপনার সিএফ ওয়ার্কার্স ফাংশন ডিপ্লয় করুন:
wrangler publish
এটি আপনাকে একটি ইউআরএল দেবে যেমন: https://waiting-room.upsdev.workers.dev/
এখন আমাদের ওয়ার্কারকে আপনার ওয়েবসাইটে রাউট করি। প্রথমে আপনার ডোমেইনের نیمসার্ভার ক্লাউডফ্লediatric আয়েন্ট করা উচিত। এটি চেক করুন। তারপর, আপনার ডোমেইনকে একটি রুট হিসেবে যোগ করুন এবং সিএফ ওয়ার্কার্স ড্যাশবোর্ডে আপনার ওয়ার্কার্স ফাংশন সিলেক্ট করুন।

উপসংহার 🎉
আমরা সফলভাবে একটি ওয়েইটিং রুম বানিয়েছি আমাদের অ্যাপ্লিকেশন কোড ছোয়া ছাড়া, ধন্যবাদ ক্লাউডফ্লেয়ার ওয়ার্কার্স এবং আপস্ট্যাশ রেডিসকে। আমরা মনে করি এটি আরেকটি প্রমাণ যে এজ ফাংশনগুলো আপস্ট্যাশের সাথে কতটা পাওয়ারফুল হয়ে ওঠে।
উন্নতির কিছু সুযোগ আছে:
- এস্টিমেটেড ওয়েইটিং টাইম: আমরা গড় ওয়েইটিং টাইম ক্যালকুলেট করে দেখাতে পারি।
- ফেয়ার এবং অর্ডারড কিউ: বর্তমানে ওয়েইটিং ভিজিটররা র্যান্ডমলি সাইটে এন্টার করছেন যখন উপলব্ধতা থাকে। আমরা একটি কিউ মেইনটেইন করতে পারি এবং ভিজিটরদের অর্ডারলি ভাবে ঢুকতে দিতে পারি।
উপরোক্ত দুটি উন্নতির জন্য আরও স্টেট রাখতে হবে এবং আরও রিমোট কল করতে হবে। তাই আমরা সেগুলো স্কিপ করতে পছন্দ করেছি। যদি আপনার ইউজ কেস স্ট্রিক্টলি সেগুলো চায়, তবে এই ব্লগ চেক করুন ক্লাউডফ্লেয়ার টিমের এন্টারপ্রাইজ সমাধানের ওয়ার্ক থেকে অনুপ্রেরণা নেওয়ার জন্য।
সোর্স কোড চেক করুন।