ডকসলিতে, আমরা ব্যবহারকারীদের গত সপ্তাহে বা মাসে প্রাপ্ত সমস্ত প্রতিক্রিয়ার সারসংক্ষেপ সহ ইমেল বিজ্ঞপ্তি পাঠাতে একটি নতুন বৈশিষ্ট্য চালু করেছি। ইমেল পাঠানো একটি নতুন সমস্যা নয়, কিন্তু আমরা এই বিষয়ে সর্বোত্তম ব্যবহারকারীর অভিজ্ঞতা প্রদান করতে চেয়েছিলাম, তাই আমরা সিদ্ধান্ত নিয়েছি যে বিজোড় সময়ে ইমেল পাঠানো এড়াতে সমস্ত ইমেল ব্যবহারকারীর টাইমজোনে পাঠানো উচিত। আমরা ব্যবহারকারীদের যে ফ্রিকোয়েন্সি দিয়ে ইমেল পেতে চান তা বেছে নেওয়ার ক্ষমতা দিতে চেয়েছিলাম। আমরা ব্যবহারকারীদের যে কোনো সময় নির্ধারিত ইমেল বিজ্ঞপ্তি বাতিল করার ক্ষমতা দিতে চেয়েছিলাম।
এই সমাধানটি বাস্তবায়ন করা কঠিন ছিল কারণ:
- আমরা আমাদের ডাটাবেসে ব্যবহারকারীর টাইমজোন সংরক্ষণ করতে চাইনি।
- এছাড়াও ইমেল পাঠানোর সময় হয়েছে কিনা তা পরীক্ষা করার জন্য আমরা প্রতি মিনিট বা ঘণ্টায় একটি ক্রোন কাজ চালাতে চাইনি৷
- এছাড়াও আমরা ব্যবহারকারীদের নির্ধারিত ইমেল বিজ্ঞপ্তি বাতিল করতে দিতে চেয়েছিলাম।
সুতরাং, আমরা একটি অনন্য সমাধান নিয়ে এসেছি:ব্যবহারকারীর টাইমজোনে ক্রন কাজের সময়সূচী করুন এবং তারপরে ব্যবহারকারী যখন ইমেল বিজ্ঞপ্তিগুলি বাতিল করে তখন ক্রোন কাজটি বাতিল করুন৷ কিন্তু একটা প্রশ্ন রয়ে গেল:কিভাবে?
আমরা ইতিমধ্যেই একটি Redis স্টোর হিসাবে Upstash ব্যবহার করছিলাম, এবং আমরা দেখতে পেয়েছি যে QStash একটি সময়সূচী বৈশিষ্ট্যও সমর্থন করে। একটু গভীরে খনন করে, আমরা দেখতে পেলাম যে QStash CRON এক্সপ্রেশনকেও সমর্থন করে। তাই, আমরা ক্রোন কাজের সময়সূচী করতে QStash ব্যবহার করার সিদ্ধান্ত নিয়েছি।
এই নিবন্ধে, আমরা আপনাকে একটি Next.js অ্যাপ্লিকেশনে QStash এবং Upstash Redis ব্যবহার করে ব্যবহারকারীর টাইমজোনে ইমেল নির্ধারণের প্রক্রিয়ার মধ্য দিয়ে নিয়ে যাব। এছাড়াও আপনি GitHub-এ সম্পূর্ণ সোর্স কোড খুঁজে পেতে পারেন।
ব্যবহারকারীর টাইমজোনে ইমেল শিডিউল করার জন্য একটি Next.js অ্যাপ্লিকেশন তৈরি করা
পূর্বশর্ত
এই টিউটোরিয়ালটি অনুসরণ করতে আপনার প্রয়োজন হবে:
- একটি Upstash অ্যাকাউন্ট
- একটি Node.js উন্নয়ন পরিবেশ
প্রকল্প সেট আপ করুন
শুরু করতে, নিম্নলিখিত কমান্ড ব্যবহার করে একটি নতুন Next.js প্রকল্প তৈরি করুন:
npx create-next-app qstash-email-scheduling এরপরে, Upstash-এর সাথে ইন্টারঅ্যাক্ট করতে নিম্নলিখিত নির্ভরতাগুলি ইনস্টল করুন:
npm install --save @upstash/redis axios
একটি নতুন .env.local তৈরি করুন আপনার প্রকল্পের রুটে ফাইল করুন এবং আপনার Upstash অ্যাকাউন্ট থেকে নিম্নলিখিত পরিবেশ ভেরিয়েবল যোগ করুন:
UPSTASH_REDIS_REST_URL=
UPSTASH_REDIS_REST_TOKEN=
QSTASH_URL=
QSTASH_TOKEN=
QSATSH_CURRENT_SIGNING_KEY=
QSATSH_NEXT_SIGNING_KEY= সমাধান ওভারভিউ
আমরা কোড বাস্তবায়ন করার আগে, এর সমাধান ওভারভিউ একবার দেখে নেওয়া যাক। আমরা তিনটি Next.js API রুট তৈরি করব:
POST /api/schedule-cron- ব্যবহারকারীর টাইমজোনে ইমেল ক্রন কাজের সময় নির্ধারণ করতে।POST /api/cancel-schedule- নির্ধারিত ইমেল ক্রোন কাজ বাতিল করতে।POST /api/send-email- ইমেল পাঠানোর জন্য নির্ধারিত ক্রন কাজের দ্বারা ট্রিগার করা হয়েছে৷
API রুটগুলি ছাড়াও, আমরা ইমেল পাওয়ার জন্য ব্যবহারকারীর পছন্দের সময় সংগ্রহ করার জন্য একটি সহজ ফর্মও তৈরি করব৷
ইউজার ইন্টারফেস তৈরি করুন
ইউজার ইন্টারফেস তৈরি করতে, আমরা app/page.tsx এ একটি নতুন পৃষ্ঠা তৈরি করব নিম্নলিখিত কোড সহ:
"use client";
import { useState } from "react";
import axios from "axios";
export default function Home() {
const userId = "tony-stark-11";
const [selectedTime, setSelectedTime] = useState("10:00");
async function createEmailNotificationSchedule() {
try {
await axios.post(
"/api/schedule-cron",
{
userId,
selectedTime,
utcOffset: new Date().getTimezoneOffset(),
},
{
headers: {
"Content-Type": "application/json",
},
},
);
alert("Email notification scheduled");
} catch (e) {
console.log("Client side error", e);
alert("Error scheduling email notification");
}
}
async function cancelEmailNotificationSchedule() {
try {
await axios.post(
"/api/cancel-schedule",
{
userId,
},
{
headers: {
"Content-Type": "application/json",
},
},
);
alert("Email notification schedule cancelled");
} catch (e) {
console.log("Client side error", e);
alert("Error scheduling email notification");
}
}
return (
<main className="mx-auto flex min-h-screen max-w-md flex-col justify-center p-24">
<h1 className="mb-4 text-xl font-bold text-neutral-600">
Email Notification for {userId}
</h1>
Send daily email summary at:
<select
onChange={(e) => setSelectedTime(e.target.value)}
className="mt-4 h-12 w-64 rounded-lg border-2 border-neutral-600 bg-neutral-800 p-2
text-white"
>
{new Array(24).fill(0).map((_, i) => {
const time = i < 10 ? `0${i}:00` : `${i}:00`;
return (
<option key={i} value={time}>
{time}
</option>
);
})}
</select>
<button
className="mt-4 rounded bg-green-700 px-4 py-2 text-white"
onClick={createEmailNotificationSchedule}
>
Schedule
</button>
<button
className="mt-4 rounded bg-red-500 px-4 py-2 text-white"
onClick={cancelEmailNotificationSchedule}
>
Cancel Schedule
</button>
</main>
);
} উপরের কোডটি একটি ড্রপ-ডাউন সহ একটি ফর্ম তৈরি করে যাতে ব্যবহারকারীরা দৈনিক ইমেল সারাংশ পাওয়ার জন্য তাদের পছন্দের সময় সেট করে। তারা এই বিজ্ঞপ্তিগুলি নির্ধারণ বা বাতিল করতে পারে এবং অ্যাপ্লিকেশনটি HTTP POST অনুরোধগুলি ব্যবহার করে সার্ভারের সাথে যোগাযোগ করে৷ আমরা নিম্নলিখিত বিভাগে HTTP এন্ডপয়েন্ট তৈরি করব।

ইমেল ক্রন কাজের সময়সূচী করুন

চলুন শুরু করা যাক POST /api/schedule-cron তৈরি করে রুট এই রুটটি ব্যবহারকারীর টাইমজোনে ইমেল ক্রন কাজের সময় নির্ধারণ করতে ব্যবহার করা হবে। ক্রোন কাজের সময়সূচী করতে আমরা QStash লাইব্রেরি ব্যবহার করব।
import { NextApiRequest, NextApiResponse } from "next";
import { Redis } from "@upstash/redis";
import axios from "axios";
export const QSTASH_CONFIG = {
QSTASH_URL: process.env.QSTASH_URL,
QSTASH_TOKEN: process.env.QSTASH_TOKEN,
QSTASH_CURRENT_SIGNING_KEY: process.env.QSTASH_CURRENT_SIGNING_KEY,
};
export const upstash = new Redis({
url: process.env.UPSTASH_REDIS_REST_URL!,
token: process.env.UPSTASH_REDIS_REST_TOKEN!,
});
// Edit this endpoint to match your domain
const SUMMARY_ENDPOINT = "https://<your-domain>/api/send-email";
export default async function scheduleSummary(
req: NextApiRequest,
res: NextApiResponse,
) {
console.log("========SCHEDULE SUMMARY========");
if (req.method !== "POST") {
return res.status(400).json({ message: "bad request" });
}
const { body } = req;
const { userId, selectedTime, utcOffset } = body;
const emailScheduleKey = `email-schedule-${userId}`;
const scheduleId = await upstash.get(emailScheduleKey);
// remove existing schedule before creating a new one
if (scheduleId) {
try {
await axios.delete(
`https://qstash.upstash.io/v1/schedules/${scheduleId}`,
{
headers: {
Authorization: `Bearer ${QSTASH_CONFIG.QSTASH_TOKEN}`,
},
},
);
} catch (e) {
console.log("Schedule not found in QStash ");
}
await upstash.del(emailScheduleKey);
}
const [hour, min] = convertToUTC(selectedTime, utcOffset).split(":");
const selectedCron = `${min} ${hour} * * *`;
// create and store new schedule
try {
const { data, status } = await axios.post(
`${QSTASH_CONFIG.QSTASH_URL}${SUMMARY_ENDPOINT}`,
{ userId },
{
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${QSTASH_CONFIG.QSTASH_TOKEN}`,
"Upstash-Cron": selectedCron,
},
},
);
console.log({ data, status });
if (data.scheduleId) {
await upstash.set(emailScheduleKey, data.scheduleId);
}
} catch (e) {
console.log({ e });
}
return res.status(200).json({ message: "success" });
}
function convertToUTC(timeString: string, utcOffset: number) {
const [hours, minutes] = timeString.split(":").map(Number);
const timeInMinutes = hours * 60 + minutes;
const utcTimeInMinutes = (timeInMinutes + utcOffset + 1440) % 1440;
const utcHours = Math.floor(utcTimeInMinutes / 60);
const utcMinutes = utcTimeInMinutes % 60;
return `${utcHours.toString().padStart(2, "0")}:${utcMinutes
.toString()
.padStart(2, "0")}`;
}
কোডের মূল হল scheduleSummary ফাংশন, যা একটি API শেষ পয়েন্ট। এটি ইনকামিং POST অনুরোধগুলি পরিচালনা করে এবং নিম্নলিখিত পদক্ষেপগুলি সম্পাদন করে:
- অনুরোধের পদ্ধতিটি যাচাই করে, এটি একটি POST অনুরোধ নিশ্চিত করে।
- ইউজারআইডি, নির্বাচিত সময় এবং utcOffset সহ অনুরোধের বডি থেকে ডেটা বের করে।
- Upstash ডাটাবেসে ব্যবহারকারীর ইমেল সময়সূচীর জন্য একটি কী তৈরি করে।
- ব্যবহারকারীর জন্য বিদ্যমান যেকোনো সময়সূচী পুনরুদ্ধার করে এবং QStash থেকে সরিয়ে দেয়।
-
convertToUTCব্যবহার করে ব্যবহারকারীর নির্বাচিত সময়কে UTC ফরম্যাটে রূপান্তর করে ফাংশন যা একটি টাইম স্ট্রিং এবং UTC অফসেট নেয়, অফসেটের জন্য হিসাব করার সময় সময়কে UTC ফর্ম্যাটে রূপান্তর করে৷ - QStash এর সময়সূচী কার্যকারিতা ব্যবহার করে ইমেল সারাংশ পাঠানোর জন্য একটি নতুন সময়সূচী তৈরি করে এবং
userIdযোগ করে পেলোড হিসাবে যে/api/send-emailএন্ডপয়েন্ট রিসিভ করে। - Upstash ডাটাবেসে নতুন তৈরি সময়সূচী আইডি সংরক্ষণ করে।
ইমেল সারাংশ পাঠান
POST /api/send-email ইমেল পাঠানোর জন্য নির্ধারিত ক্রন কাজের দ্বারা রুট ট্রিগার করা হবে। আমরা @upstash/qstash/nextjs ব্যবহার করব অনুরোধের স্বাক্ষর যাচাই করার জন্য লাইব্রেরি। এটি নিশ্চিত করবে যে অনুরোধটি QStash থেকে আসছে এবং অন্য কোনো উত্স থেকে নয়।
POST /api/send-email ফাংশন userId পায় অনুরোধের শরীরে। আপনি userId এর উপর ভিত্তি করে ইমেল প্রস্তুত এবং প্রেরণের জন্য একটি ফাংশন বাস্তবায়ন করতে পারেন .
import { NextApiRequest, NextApiResponse } from "next";
import { verifySignature } from "@upstash/qstash/nextjs";
async function handler(request: NextApiRequest, res: NextApiResponse) {
console.log("==========Project summary handler==========");
if (request.method !== "POST") {
return res.status(400).json({ message: "bad request" });
}
const { body } = request;
const { userId } = body;
// prepare and send email
return res.status(200).json({ message: "success" });
}
export default verifySignature(handler);
export const config = {
api: {
bodyParser: false,
},
}; নির্ধারিত ইমেল ক্রন কাজ বাতিল করুন

এর পরে, আসুন POST /api/cancel-schedule তৈরি করি রুট এই রুটটি নির্ধারিত ইমেল ক্রন কাজ বাতিল করতে ব্যবহার করা হবে। ক্রোন কাজ বাতিল করতে আমরা QStash লাইব্রেরি ব্যবহার করব।
import { NextApiRequest, NextApiResponse } from "next";
import axios from "axios";
import { Redis } from "@upstash/redis";
export const QSTASH_CONFIG = {
QSTASH_URL: process.env.QSTASH_URL,
QSTASH_TOKEN: process.env.QSTASH_TOKEN,
QSTASH_CURRENT_SIGNING_KEY: process.env.QSTASH_CURRENT_SIGNING_KEY,
};
export const upstash = new Redis({
url: process.env.UPSTASH_REDIS_REST_URL!,
token: process.env.UPSTASH_REDIS_REST_TOKEN!,
});
export default async function scheduleSummary(
req: NextApiRequest,
res: NextApiResponse
) {
console.log("========REMOVE SCHEDULE SUMMARY========");
if (req.method !== "POST") {
return res.status(400).json({ message: "bad request" });
}
const { body } = req;
const { userId } = body;
const emailScheduleKey = `email-schedule-${userId}`;
const scheduleId = await upstash.get(emailScheduleKey);
// remove existing schedule before creating a new one
if (scheduleId) {
try {
await axios.delete(
`https://qstash.upstash.io/v1/schedules/${scheduleId}`,
{
headers: {
Authorization: `Bearer ${QSTASH_CONFIG.QSTASH_TOKEN}`,
},
}
);
} catch (e) {
console.log("Schedule not found in QStash ");
}
await upstash.del(emailScheduleKey);
}
return res.status(200).json({ message: "success" });
} উপসংহার
সংক্ষেপে, আমরা Upstash Redis এবং QStash ব্যবহার করে ব্যবহারকারীর টাইমজোনে ইমেলগুলি নির্ধারণ করতে সক্ষম হয়েছি। আমরা আমাদের ডাটাবেসে ব্যবহারকারীর টাইমজোন সংরক্ষণ না করেই এটি অর্জন করেছি। আমরা ব্যবহারকারীদের যে কোনো সময় নির্ধারিত ইমেল বিজ্ঞপ্তি বাতিল করার ক্ষমতা দিতে সক্ষম হয়েছি।
আপনি যদি আপনার পণ্যের জন্য ডকুমেন্টেশন বজায় রাখেন, আপনার ডকসলি চেক করা উচিত। এটি একটি ফিডব্যাক টুল যা প্রযুক্তিগত ডকুমেন্টেশনের জন্য তৈরি করা হয়েছে যা আপনাকে আপনার ব্যবহারকারীদের কাছ থেকে প্রতিক্রিয়া সংগ্রহ করতে এবং সেগুলিকে কার্যকরী অন্তর্দৃষ্টিতে পরিণত করতে সহায়তা করে৷