রপ্তানি টাইমআউট প্রতিরোধ: অ্যাসিঙ্ক জব, প্রগতি, স্ট্রিমিং
বড় CSV ও PDF রিপোর্টের জন্য async export job, প্রগতি সূচক, পেজিনেশন ও স্ট্রিমিং ডাউনলোড ব্যবহার করে এক্সপোর্ট টাইমআউট প্রতিরোধ করুন।

কেন রপ্তানি টাইমআউট করে সাধারণ ভাষায়
একটি রপ্তানি টাইমআউট করে যখন সার্ভার নির্ধারিত সময়সীমার মধ্যে কাজ শেষ করতে পারে না। সেই সময়সীমা আপনার ব্রাউজার, একটি রিভার্স প্রোক্সি, অ্যাপ সার্ভার, বা ডাটাবেস কানেকশনের দ্বারা নির্ধারিত হতে পারে। ব্যবহারকারীর দৃষ্টিতে এটা প্রায়ই র্যান্ডম মনে হয়, কারণ কখনো রপ্তানি কাজ করে এবং কখনো ব্যর্থ হয়।
স্ক্রিনে এটি সাধারণত এমনভাবে দেখা যায়:
- একটি স্পিনার যা কখনই শেষ হয় না
- একটি ডাউনলোড শুরু হয়, তারপর "network error" দিয়ে থেমে যায়
- দীর্ঘ অপেক্ষার পর একটি এরর পেজ
- একটি ফাইল ডাউনলোড হয় কিন্তু খালি বা ক্ষতিগ্রস্ত
বড় রপ্তানিগুলো চাপ বেশ কয়েকটি সিস্টেম অংশে একসাথে দেয়। ডাটাবেসকে অনেক রো খুঁজে একত্র করতে হয়। অ্যাপ সার্ভারকে সেগুলো CSV-তে ফরম্যাট বা PDF-এ রেন্ডার করতে হয়। তারপর ব্রাউজারকে একটা বড় রেসপন্স গ্রহণ করতে হবে না যাতে কানেকশন ড্রপ করে।
বৃহৎ ডেটাসেটই মূল ট্রিগার হতে পারে, কিন্তু "ছোট" এক্সপোর্টও ভারী হতে পারে। দামী joins, অনেক ক্যালকুলেটেড ফিল্ড, প্রতিটি রো-র জন্য লুকআপ, ও খারাপ ইন্ডেক্স করা ফিল্টার সাধারণ রিপোর্টকে টাইমআউটে পরিণত করতে পারে। PDF বিশেষভাবে ঝুঁকিপূর্ণ কারণ এতে লেআউট, ফন্ট, ছবি, পেজ ব্রেক এবং প্রায়ই সম্পর্কিত ডেটা আনতে অতিরিক্ত কুয়েরি লাগে।
রিটারির ফলে প্রায়ই অবস্থা খারাপ হয়। যখন ব্যবহারকারী রিফ্রেশ করে বা আবার Export চাপেন, আপনার সিস্টেম একই কাজ আবার শুরু করতে পারে। এখন ডাটাবেস ডুপ্লিকেট কুয়েরি চালায়, অ্যাপ সার্ভার ডুপ্লিকেট ফাইল তৈরি করে, এবং সিস্টেম যখন ইতোমধ্যেই সমস্যায় তখনই লোড বাড়ে।
রপ্তানি টাইমআউট প্রতিরোধ করতে চাইলে, একটি রপ্তানি সাধারণ পেজ লোডের মতো ভাববেন না—একটা ব্যাকগ্রাউন্ড টাস্ক হিসেবে বিবেচনা করুন। এমনকি একটি no-code বিল্ডার যেমন AppMaster-এও প্যাটার্নই বেশি গুরুত্বপূর্ণ: বড় কাজের জন্য আলাদা ফ্লো দরকার, না যে "বাটন ক্লিক, রেসপন্সের জন্য অপেক্ষা"।
আপনার অ্যাপের জন্য সঠিক এক্সপোর্ট প্যাটার্ন নির্বাচন
বেশিরভাগ রপ্তানি ব্যর্থতা হয় কারণ অ্যাপ সব পরিস্থিতির জন্য একই প্যাটার্ন ব্যবহার করে, যদিও ডেটার আকার ও প্রসেসিং সময় অনেক আলাদা।
একটি সরল synchronous এক্সপোর্ট (ব্যবহারকারী ক্লিক করে, সার্ভার জেনারেট করে, ডাউনলোড শুরু হয়) ছোট ও পূর্বানুমেয় এক্সপোর্টের জন্য ঠিক আছে। ভাবুন কয়েকশো রো, বেসিক কলাম, ভারী ফরম্যাটিং নেই, এবং একই সময়ে অতি বেশি ব্যবহারকারী নেই। যদি এটি নিয়মিত কয়েক সেকেন্ডে শেষ হয়, সহজ পদ্ধতি সাধারণত ভাল।
কোনো কিছু লম্বা বা অপ্রেডিক্টেবল হলে async export jobs ব্যবহার করুন। এটা বড় ডেটাসেট, জটিল ক্যালকুলেশন, PDF লেআউট কাজ, এবং শেয়ার করা সার্ভারের জন্য উপযুক্ত যেখানে একটি ধীর এক্সপোর্ট অন্যান্য রিকোয়েস্ট ব্লক করতে পারে।
Async jobs উপযুক্ত যখন:
- রপ্তানি নিয়মিত 10–15 সেকেন্ডের বেশি সময় নেয়
- ব্যবহারকারীরা বড় তারিখ পরিসর বা "all time" চান
- আপনি চার্ট, ছবি বা বহু পেজ সহ PDF তৈরি করেন
- একাধিক টিম পিক আওয়ারসে এক্সপোর্ট করে
- ব্যর্থ হলে নিরাপদভাবে retry করতে চান
স্ট্রিমিং ডাউনলোডও সহায়ক হতে পারে যখন এক্সপোর্ট বড় কিন্তু ক্রমানুসারে তৈরি করা যায়। সার্ভার প্রথম থেকেই বাইট পাঠানো শুরু করে, যা দ্রুত মনে হয় এবং পুরো ফাইল মেমরিতে বানানোর দরকার কমায়। এটা দীর্ঘ CSV ডাউনলোডের জন্য চমৎকার, কিন্তু যদি প্রথম লাইনের আগে সবকিছু হিসাব করা লাগে তবে কম সহায়ক হবে।
আপনি পদ্ধতিগুলো মিলিয়ে ব্যবহার করতে পারেন: async জব চালিয়ে এক্সপোর্ট তৈরি (বা স্ন্যাপশট প্রস্তুত) করুন, তারপর যখন প্রস্তুত তখন স্ট্রিম করে ডাউনলোড দিন। AppMaster-এ একটি ব্যবহারিক পন্থা হলো একটি "Export Requested" রেকর্ড তৈরি করা, ব্যাকএন্ড বিজনেস প্রসেসে ফাইল জেনারেট করা, এবং ব্যবহারকারীকে ব্রাউজার রিকোয়েস্ট খোলা না রেখে প্রস্তুত ফাইল ডাউনলোড করার সুযোগ দেওয়া।
ধাপে ধাপে: একটি async export job তৈরি করা
সবচেয়ে বড় পরিবর্তনটি সহজ: ব্যবহারকারীর ক্লিকের সাথে একই রিকোয়েস্টে ফাইল জেনারেট করা বন্ধ করুন।
একটি async export job কাজটি দুটি অংশে ভাগ করে: দ্রুত একটি অনুরোধ যা জব তৈরি করে, এবং ব্যাকগ্রাউন্ডে কাজ যা ফাইল তৈরি করে যাতে অ্যাপ প্রতিক্রিয়াশীল থাকে।
একটি ব্যবহারিক 5-ধাপের ফ্লো
- এক্সপোর্ট অনুরোধ ক্যাপচার করুন (কে অনুরোধ করেছে, ফিল্টার, নির্বাচিত কলাম, আউটপুট ফর্ম্যাট)।
- একটি জব রেকর্ড তৈরি করুন যাতে status (queued, running, done, failed), টাইমস্ট্যাম্প, এবং একটি error ফিল্ড থাকে।
- চ pesado কাজ ব্যাকগ্রাউন্ডে চালান—কিউ, নির্ধারিত ওয়ার্কার, বা ডেডিকেটেড ওয়ার্কার প্রসেস ব্যবহার করে।
- ফলাফল স্টোরেজে লিখুন (object storage বা ফাইল স্টোর), তারপর জব রেকর্ডে একটি ডাউনলোড রেফারেন্স সংরক্ষণ করুন।
- ব্যবহারকারীকে প্রস্তুত হলে in-app নোটিফিকেশন, ইমেইল, বা দলের পরিচিত একটি মেসেজ চ্যানেলের মাধ্যমে জানান।
জব রেকর্ডকেই আপনার সত্যের উৎস রাখুন। ব্যবহারকারী রিফ্রেশ করলেও, ডিভাইস বদলালেও, বা ট্যাব বন্ধ করলেও একই জব স্ট্যাটাস ও একই ডাউনলোড বাটন দেখানো সম্ভব।
উদাহরণ: একটি সাপোর্ট ম্যানেজার গত ত্রৈমাসিকের সমস্ত টিকিট এক্সপোর্ট করেন। স্পিনিং ট্যাবের ওপর অপেক্ষা না করে, তারা একটি জব এন্ট্রি দেখেন যা queued থেকে done-এ যায়, এবং তারপর ডাউনলোড উপস্থিত হয়। AppMaster-এ আপনি Data Designer-এ জব টেবিল মডেল করতে পারেন, Business Process Editor-এ ব্যাকগ্রাউন্ড লজিক বানাতে পারেন, এবং একটি status ফিল্ড UI-র স্টেট চালাতে ব্যবহার করতে পারেন।
ব্যবহারকারীরা বিশ্বাস করে এমন প্রগতি সূচক
একটি ভাল প্রগতি সূচক উদ্বেগ কমায় এবং মানুষকে Export পাঁচ বার চাপা থেকে বিরত রাখে। এটি রপ্তানি টাইমআউটকে পরোক্ষভাবে কমায়, কারণ যখন অ্যাপ বাস্তব অগ্রগতি দেখায় ব্যবহারকারীরা অপেক্ষা করতে রাজি থাকে।
মানুষ বুঝবে এমনভাবে প্রগতি দেখান। কেবল শতাংশ প্রায়ই বিভ্রান্ত করে, তাই এটি কিছু কংক্রিটের সাথে জোড়া দিন:
- বর্তমান ধাপ (Preparing data, Fetching rows, Building file, Uploading, Ready)
- প্রক্রিয়াজাত রো সংখ্যা মোটের বিপরীতে (বা পেজ করা পেজের সংখ্যা)
- কাজ শুরু হওয়ার সময় ও শেষ আপডেট
- আনুমানিক বাকী সময় (যদি এটি স্থির থেকে যায়)
মিথ্যা নির্ভুলতা এড়ান। যদি মোট কাজ এখনও অজানা হয়, 73% দেখাবেন না। প্রথমে মাইলস্টোন দেখান, তারপর ডিনোমিনেটর জানা গেলে শতাংশ দেখান। একটি সাধারণ প্যাটার্ন হলো সেটআপের জন্য 0% থেকে 10%, রো প্রক্রিয়াজাতের উপর 10% থেকে 90%, এবং ফাইল ফাইনালাইজেশনের জন্য 90% থেকে 100%। পরিবর্তনশীল পেজ সাইজের PDF-এর ক্ষেত্রে ছোট সত্ তথ্য টানুন যেমন "records rendered" বা "sections completed"।
প্রতিনিয়ত আপডেট দিন যাতে তা জীবন্ত মনে হয়, কিন্তু এত ঘনভাবে নয় যে ডাটাবেস বা কিউ হিট হয়। সাধারণত প্রতি 1–3 সেকেন্ডে বা প্রতি N রেকর্ড (যেমন প্রতি 500 বা 1,000 রো) আপডেট লেখা হয়, যা কম ঘন ঘন। এছাড়া একটি হালকা-weight heartbeat timestamp রাখুন যাতে UI বলতে পারে "এখানেই কাজ চলছে" এমনকি যখন শতাংশ ঠিক না বাড়ে।
ব্যবহারকারীদের নিয়ন্ত্রণ দিন যখন কাজ প্রত্যাশার তুলনায় বেশি সময় নেয়। চলমান এক্সপোর্ট ক্যানসেল করার সুযোগ দিন, নতুনটি চালু করার অনুমতি দিন পুরানোটি হারানোর দরকার না পড়ে, এবং রপ্তানি ইতিহাস দেখার বিকল্প দিন স্ট্যাটাস (Queued, Running, Failed, Ready) ও সংক্ষিপ্ত এরর মেসেজসহ।
AppMaster-এ একটি সাধারণ রেকর্ড দেখতে পারে ExportJob (status, processed_count, total_count, step, updated_at)। UI ঐ রেকর্ড পোল করে এবং async জব ব্যাকগ্রাউন্ডে ফাইল তৈরি করার সময় সত্যিকারের প্রগতি দেখায়।
কাজ সীমিত রাখতে pagination ও filtering
বেশিরভাগ রপ্তানি টাইমআউট ঘটে কারণ এক্সপোর্ট সবকিছু একসাথে করতে চায়: অনেক রো, অনেক কলাম, অনেক joins। দ্রুততম সমাধান হলো কাজকে সীমিত রাখা যাতে ব্যবহারকারী ছোট ও পরিষ্কার ডেটাসেট এক্সপোর্ট করে।
ব্যবহারকারীর লক্ষ্য থেকে শুরু করুন। কেউ যদি "গত মাসের ব্যর্থ ইনভয়েস" দরকার বলে, তাহলে ডিফল্টভাবে "সব ইনভয়েস কখনও" দেখাবেন না। ফিল্টারগুলো স্বাভাবিক মনে করান, ব্যস্ততার কাজ মনে করাবেন না। একটি সহজ তারিখ পরিসর এবং একটি স্টেট ফিল্টার প্রায়ই ডেটাসেট 90% কমিয়ে দেয়।
একটি ভাল এক্সপোর্ট ফর্ম সাধারণত একটি তারিখ পরিসর (বুদ্ধিমান ডিফল্ট যেমন গত 7 বা 30 দিন), এক বা দুইটি মূল স্টেট, ঐচ্ছিক সার্চ বা কাস্টমার/টিম সিলেকশন, ও সম্ভব হলে একটি কনট রিভিউ (এস্টিমেটও চলবে) রাখে।
সার্ভার সাইডে, পেজিং ব্যবহার করে চাঙ্কে ডেটা পড়ুন। এতে মেমরি স্থিতিশীল থাকে এবং প্রগতির প্রাকৃতিক চেকপয়েন্ট দেয়। পেজিং করার সময় স্থিতিশীল অর্ডার ব্যবহার করুন (উদাহরণ: created_at, তারপর id)—নারীর অভাবে নতুন রো আগের পেজে ঢুকে যেতে পারে এবং আপনি রেকর্ড মিস বা ডুপ্লিকেট পেতে পারেন।
দীর্ঘ রপ্তানির সময় ডেটা বদলায়, তাই সিদ্ধান্ত নিন "consistent" মানে কি। একটি সহজ উপায় হলো জব শুরুতে একটি snapshot সময় রেকর্ড করা এবং তারপর শুধুমাত্র ঐ টাইমস্ট্যাম্প পর্যন্ত রো এক্সপোর্ট করা। যদি কঠোর কনসিস্টেন্সি দরকার হয়, আপনার ডাটাবেস সমর্থন করলে consistent read বা ট্রানজেকশন ব্যবহার করুন।
একটি no-code টুল যেমন AppMaster-এ এটি সহজে মিলেযায়: একটি বিজনেস প্রসেসে ফিল্টার ভ্যালিডেট করুন, snapshot time সেট করুন, তারপর পেজ ধরে লুপ চালান যতক্ষণ ডেটা ফেচ করা শেষ না হয়।
সার্ভার ভাঙা ছাড়াই Streaming ডাউনলোড
স্ট্রিমিং মানে আপনি ফাইল তৈরি হতে থাকা অবস্থায়ই ব্যবহারকারীর কাছে পাঠানো শুরু করবেন। সার্ভার পুরো CSV বা PDF একবারে মেমরিতে ধরে রাখার দরকার পড়ে না। বড় ফাইলের ক্ষেত্রে টাইমআউট প্রতিরোধের অন্যতম নির্ভরযোগ্য উপায় এটি।
স্ট্রিমিং ধীর কুয়েরিকে দ্রুত করে না। যদি ডাটাবেস কাজ প্রথম বাইটের আগে পাঁচ মিনিট নেয়, রিকোয়েস্ট তখনও টাইমআউট হতে পারে। সাধারণ সমাধান হলো স্ট্রিমিংকে পেজিংয়ের সাথে জোড়া করা: একটি চাঙ্ক ফেচ করুন, লিখুন, এবং যেতে থাকুন।
মেমরি কম রাখতে, যেভাবে তৈরি হয় সেভাবে লিখুন। একটি চাঙ্ক (উদাহরণ: 1,000 CSV রো বা একটি PDF পেজ) জেনারেট করে রেসপন্সে লিখুন, তারপর flush করুন যাতে ক্লায়েন্ট ডেটা পায়। বড় অ্যারে করে সব রো জমা করে পরে stringify করা এড়িয়ে চলুন। স্টেবল অর্ডার দরকার হলে ডাটাবেসে সঠিকভাবে sort করুন।
হেডার, নাম, ও কনটেন্ট টাইপ
ব্রাউজার ও মোবাইল অ্যাপে ডাউনলোড ঠিকভাবে হ্যান্ডেল করতে স্পষ্ট হেডার ব্যবহার করুন। সঠিক কনটেন্ট টাইপ সেট করুন (যেমন text/csv বা application/pdf) এবং একটি নিরাপদ ফাইলনেম দিন। ফাইলনেমে বিশেষ ক্যারেক্টার এড়িয়ে চলুন, সংক্ষিপ্ত রাখুন, এবং ব্যবহারকারীরা একই রিপোর্ট বারবার এক্সপোর্ট করলে টাইমস্ট্যাম্প যোগ করুন।
Resume ও পার্শিয়াল ডাউনলোড
প্রারম্ভে সিদ্ধান্ত নিন আপনি resume সমর্থন করবেন কি না। বেসিক স্ট্রিমিং সাধারণত byte-range resume সমর্থন করে না, বিশেষত জেনারেট করা PDF-গুলোর জন্য। যদি আপনি resume সমর্থন করেন, তাহলে Range অনুরোধ হ্যান্ডেল করতে হবে এবং একই জবের জন্য ধারাবাহিক আউটপুট জেনারেট করতে হবে।
শিপ করার আগে নিশ্চিত করুন:
- দেহ লেখার আগে হেডার পাঠান, তারপর চাঙ্ক করে লিখে flush করুন
- চাঙ্ক সাইজ স্থিতিশীল রাখুন যাতে লোডে মেমরি সমতল থাকে
- আউটপুট বিশ্বাসযোগ্য করতে deterministic অর্ডার ব্যবহার করুন
- resume সমর্থিত কি না এবং কানেকশন ড্রপ হলে কি হবে তা ডকুমেন্ট করুন
- সার্ভার-সাইড সীমা যোগ করুন (max rows, max time) এবং সীমাপ্রাপ্ত হলে বন্ধুত্বপূর্ণ এরর ফিরিয়ে দিন
AppMaster-এ এক্সপোর্ট তৈরি করলে জেনারেশন লজিক ব্যাকএন্ড ফ্লোতে রাখুন এবং ব্রাউজার থেকে স্ট্রিম না করে সার্ভার-সাইড থেকে স্ট্রিম করুন।
বড় CSV এক্সপোর্ট: ব্যবহারিক কৌশল
বড় CSV-র ক্ষেত্রে ফাইলকে একটিবারের ব্লব হিসেবে ভাবা বন্ধ করুন। এটাকে লুপ হিসেবে বানান: ডেটার একটি স্লাইস পড়ুন, রো লিখুন, পুনরাবৃত্তি করুন। এতে মেমরি সমতল থাকে এবং retry গুলো নিরাপদ হয়।
CSV রো একটি-এক করে লিখুন। যদিও আপনি async জব-এ এক্সপোর্ট করছেন, তা সত্ত্বেও "সব রো জড়ো করে তারপর stringify" এড়িয়ে চলুন। একটি রাইটার খুলে প্রতিটি রো প্রস্তুত হওয়া মাত্র append করুন। আপনার স্ট্যাক যদি সমর্থন করে, ডাটাবেস কার্সার ব্যবহার করুন অথবা রেকর্ড পেজ করে নিন যাতে কখনই মিলিয়ন রেকর্ড একসাথে লোড না হয়।
CSV সঠিকতা যেমনই দ্রুততা, সমান গুরুত্বপূর্ণ। ফাইল ঠিকঠাক মনে হলেও কেউ Excel-এ খুললে কলাম ঢিলে পড়তে পারে।
CSV বিধি যা ভাঙা ফাইল বন্ধ করে
- কমা, কোট ও নিউলাইন সবসময় escape করুন (পুরো ফিল্ডটি ডাবল কোটে বাধা দিন, এবং ভিতরের ডাবল কোটগুলো ডাবল করে দিন)
- UTF-8 আউটপুট করুন এবং অ-ইংরেজি নাম সারা পথে টেস্ট করুন
- একটি স্থিত হেডার রো রাখুন এবং রানগুলোর মাধ্যমে কলামের অর্ডার অপরিবর্তিত রাখুন
- তারিখ ও দশমিক নম্বর নর্মালাইজ করুন (একটি ফরম্যাট বেছে নিয়ে অনুগত থাকুন)
- ডেটা যদি =, +, -, বা @ দিয়ে শুরু করতে পারে তবে ফর্মুলা থেকে বিরত থাকুন
পারফরম্যান্স সাধারণত লেখা নয়, ডেটা অ্যাকসেসে মারা যায়। N+1 লুকআপ (যেমন লুপের ভেতর প্রতিটি কাস্টমার লোড করা) লক্ষ্য রাখুন। প্রাসঙ্গিক ডেটা এক কুয়েরিতে ফেচ করুন, অথবা আগেই preload করুন, তারপর রো লিখুন।
যখন রপ্তানি সত্যিই বিশাল, সেগুলো উদ্দেশ্যপুর্নভাবে ভাগ করুন। ব্যবহারিক পন্থা হলো মাসভিত্তিক, কাস্টমারভিত্তিক, বা এন্টিটি টাইপভিত্তিক একটি ফাইল করা। "5 বছর অর্ডার" এক্সপোর্ট 60টি মাসিক ফাইলে ভাগ করা যেতে পারে, প্রতিটি স্বাধীনভাবে জেনারেট হবে যাতে একটি ধীর মাস সবকিছুকে ব্লক না করে।
AppMaster ব্যবহারে, Data Designer-এ dataset মডেল করুন এবং ব্যাকগ্রাউন্ড বিজনেস প্রসেস হিসাবে এক্সপোর্ট চালান, পেজিং করে রো লিখুন।
বড় PDF এক্সপোর্ট: নির্ভরযোগ্য রাখুন
PDF জেনারেশন CSV-এর তুলনায় সাধারণত ধীর কারণ এটি CPU-নির্ভর—আপনি শুধু ডেটা সরাচ্ছেন না, পেজ লেআউট, ফন্ট বসানো, টেবিল আঁকা, এবং প্রায়ই ছবি রিসাইজ করছেন। PDF-কে ব্যাকগ্রাউন্ড টাস্ক হিসেবে বিবেচনা করুন এবং স্পষ্ট সীমা রাখুন।
টেমপ্লেট পছন্দই নির্ধারণ করে একটি 2-মিনিট এক্সপোর্ট 20-মিনিটে পরিণত হবে কি না। সহজ লেআউট জিতবে: কম কলাম, কম nested টেবিল, ও পূর্বানুমেয় পেজ ব্রেক। ছবি সবচেয়ে দ্রুত সবকিছু ধীর করে দেয়, বিশেষত যদি সেগুলো বড়, উচ্চ DPI, বা রেন্ডারের সময় রিমোট স্টোরেজ থেকে আনা হয়।
টেমপ্লেট সিদ্ধান্ত যা সাধারণত গতি ও নির্ভরযোগ্যতা বাড়ায়:
- এক বা দুইটি ফন্ট ব্যবহার করুন এবং ভারী fallback চেইন এড়ান
- হেডার ও ফুটার সাদাসিধা রাখুন (প্রতিটি পৃষ্ঠায় ডাইনামিক চার্ট এড়ান)
- বড় র্যাস্টার ছবির পরিবর্তে ভেক্টর আইকন প্রাধান্য দিন
- এমন "auto fit" লেআউট এড়ান যা অনেকবার টেক্সট মেজার করে
- জটিল ট্রান্সপারেন্সি ও শ্যাডো এড়ান
বড় এক্সপোর্টের জন্য ব্যাচে রেন্ডার করুন। একটি সেকশন বা ছোট পেজ রেঞ্জ একবারে জেনারেট করুন, তা টেম্প ফাইলে লিখুন, তারপর শেষ PDF অ্যানসেম্বলে যোগ করুন। এতে মেমরি স্থিতিশীল থাকে এবং ওয়ার্কার ক্র্যাশ করলে retry নিরাপদ হয়। এটি async জব ও স্পষ্ট প্রগতির সাথে ভালভাবে যায় (উদাহরণ: "Preparing data", "Rendering pages 1-50", "Finalizing file")।
প্রশ্ন করুন: ব্যবহারকারী কি সত্যিই PDF চাইছেন? যদি তারা মূলত বিশ্লেষণের জন্য রো এবং কলাম চান, তাহলে CSV অফার করুন পাশাপাশি "Export PDF"। সারাংশ PDF ছোট রাখতে পারেন যখন সম্পূর্ণ ডেটাসেট CSV-তে থাকে।
AppMaster-এ এটি স্বাভাবিকভাবে মেলে: PDF জেনারেট ব্যাকগ্রাউন্ড জব হিসেবে চালান, প্রগতি রিপোর্ট করুন, এবং জব শেষ হলে ডাউনলোড দিলেই হবে।
টাইমআউট ঘটাতে সাধারণ ভুলগুলো
রপ্তানি ব্যর্থতা সাধারণত রহস্যজনক নয়। কয়েকটি পছন্দ 200 রো-তে ঠিক চলে, তারপর 200,000 এ ভেঙে পড়ে।
সাবসচর্যা ভুলগুলো:
- পুরো এক্সপোর্ট এক ওয়েব রিকোয়েস্টের ভেতর চালানো। ব্রাউজার অপেক্ষা করে, সার্ভারের ওয়ার্কার ব্যস্ত থাকে, এবং কোনো ধীর কুয়েরি বা বড় ফাইল টাইমলিমিট ছাড়িয়ে দেয়।
- সময়ের ওপর ভিত্তি করে প্রগতি দেখানো। একটি টাইমার যা 90% পর্যন্ত দৌড়ায় তারপর আটকে যায় ব্যবহারকারীকে রিফ্রেশ বা ক্যানসেল বা আবার শুরু করতে দেয়।
- ফাইল লেখার আগে সব রো মেমরিতে পড়ে নেওয়া। ইমপ্লিমেন্ট করা সহজ, কিন্তু মেমরি লিমিটে পৌঁছানোর দ্রুত উপায়।
- দীর্ঘ ডাটাবেস ট্রানজেকশন ধরে রাখা বা লক উপেক্ষা করা। এক্সপোর্ট কুয়েরি লেখাগুলো ব্লক করতে পারে, বা লেখাগুলো তাকে ব্লক করতে পারে, এবং ধীরতা পুরো অ্যাপে ছড়ায়।
- সীমাহীন এক্সপোর্ট অনুমতি দেয়া ও ক্লিনআপ না রাখা। বারবার ক্লিক করলে জব জমে, স্টোরেজ ভর্তি হয়, এবং পুরনো ফাইল চারাও থাকে।
একটি বাস্তব উদাহরণ: একটি সাপোর্ট লিড গত দুই বছরের জন্য সব টিকিট এক্সপোর্ট করে এবং কারণ কিছু দেখায় না বলে দুইবার ক্লিক করে। এখন দুইটি অভিন্ন এক্সপোর্ট একই ডাটাবেস কুয়েরির জন্য প্রতিযোগিতা করে, দুটো বৃহৎ ফাইল মেমরিতে তৈরি করে, এবং উভয়ই টাইমআউট হয়।
কোনো no-code টুলে যেমন AppMaster-এ নির্মাণ করলেও একই নিয়ম প্রযোজ্য: রপ্তানিকে রিকোয়েস্ট পাথ থেকে বের করুন, প্রগতি রো-ভিত্তিক ট্র্যাক করুন, আউটপুট লিখে যান, এবং ব্যবহারকারীর প্রতি কতগুলো এক্সপোর্ট একই সাথে চলতে পারে তা সীমাবদ্ধ করুন।
শিপিংয়ের আগে দ্রুত চেকলিস্ট
প্রোডাকশনে এক্সপোর্ট ফিচার রিলিজ করতে আগে টাইমার-মাইন্ডসেট নিয়ে দ্রুত একটি পাস করুন। বড় কাজ রিকোয়েস্টের বাইরে চলে, ব্যবহারকারীরা সৎ প্রগতি দেখে, এবং সার্ভার সবকিছু একসাথে করার চেষ্টা করে না।
দ্রুত প্রি-ফ্লাইট চেকলিস্ট:
- বড় এক্সপোর্ট ব্যাকগ্রাউন্ড জব হিসেবে চলে (ছোটগুলো যদি বিশ্বস্তভাবে দ্রুত শেষ হয় তাহলে synchronous ঠিক)
- ব্যবহারকারী স্পষ্ট স্টেট দেখে যেমন queued, running, done, failed, টাইমস্ট্যাম্পসহ
- ডেটা চাঙ্কে পড়া হয় এবং স্থিতিশীল sort order আছে (উদাহরণ: created time + ID)
- শেষ ফাইল পরে ডাউনলোড করা যায় পুনরায় রানে না দিয়ে, এমনকি ব্যবহারকারী ট্যাব বন্ধ করলেও
- পুরনো ফাইল ও জব ইতিহাসের জন্য সীমা ও ক্লিনআপ পরিকল্পনা আছে (বয়স-ভিত্তিক মুছে ফেলা, প্রতি ব্যবহারকারী/খাতায় সর্বাধিক জব, স্টোরেজ ক্যাপ)
একটি ভাল স্যানিটি চেক হলো আপনার সবচেয়ে খারাপ কেস চেষ্টা করা: আপনি যে সবচেয়ে বড় ডেটা রেঞ্জ অনুমোদন করেন তা এক্সপোর্ট করুন যখন আর কেউ একই সময়ে রেকর্ড যোগ করছে। যদি আপনি ডুপ্লিকেট, মিসিং রো, বা আটকে থাকা প্রগতি দেখেন, আপনার অর্ডারিং বা চাঙ্কিং স্থিতিশীল নেই।
AppMaster-এ এই চেকগুলো বাস্তবে করা সহজ: Business Process Editor-এ ব্যাকগ্রাউন্ড প্রসেস, আপনার ডাটাবেসে একটি ExportJob রেকর্ড, এবং UI যে স্ট্যাটাস পড়ে এবং রিফ্রেশ করে।
ব্যর্থতা নিরাপদ মনে করান। একটি ব্যর্থ জব তার এরর মেসেজ রাখা উচিত, retry দেওয়া উচিত, এবং অসম্পূর্ণ ফাইল "সম্পন্ন" মনে হওয়ার মতো তৈরি হওয়া এড়ানো উচিত।
উদাহরণ: বছরের ডেটা রপ্তানি করে অ্যাপ ফ্রিজ না করা
একটি অপস ম্যানেজার প্রতি মাসে দুটি এক্সপোর্ট করে: বিশ্লেষণের জন্য গত 2 বছরের অর্ডারের CSV, এবং হিসাবরক্ষণের জন্য মাসিক ইনভয়েস PDF-এর সেট। যদি আপনার অ্যাপ সাধারণ ওয়েব রিকোয়েস্টে এগুলো বানানোর চেষ্টা করে, একদিন আপনি টাইমলিমিটে পড়বেন।
প্রথমে কাজকে সীমাবদ্ধ করুন। এক্সপোর্ট স্ক্রিনটি একটি তারিখ রেঞ্জ (ডিফল্ট: গত 30 দিন), ঐচ্ছিক ফিল্টার (স্ট্যাটাস, এলাকা, সেলস রিপ), এবং পরিষ্কার কলামের পছন্দ দেয়। এই এক পরিবর্তন প্রায়ই 2-বছর, 2-মিলিয়ন রো সমস্যাকে পরিচালনাযোগ্য করে তোলে।
ব্যবহারকারী Export চাপলে অ্যাপ একটি Export Job রেকর্ড তৈরি করে (type, filters, requested_by, status, progress, error_text) এবং এটিকে কিউতে দেয়। AppMaster-এ এটি Data Designer মডেল + ব্যাকগ্রাউন্ড Business Process।
জব চলাকালে UI ব্যবহারকারীকে এমন একটি নির্ভরযোগ্য স্টেট দেখায়: queued, processing (উদাহরণ: 3 of 20 chunks), generating file, ready (ডাউনলোড বাটন), বা failed (সংক্ষিপ্ত এরর এবং retry)।
Chunking হল কীয়ার বিস্তারিত। CSV জব অর্ডারগুলো পেজে পড়ে (ধরা যাক প্রতি পেজে 50,000), প্রতিটি পেজ আউটপুটে লেখে, এবং প্রতিটি চাঙ্ক শেষে প্রগতি আপডেট করে। PDF জব এভাবেই কাজ করে কিন্তু প্রতিটি ইনভয়েস ব্যাচ (উদাহরণ: এক মাস) অনুসারে, যাতে একটি ধীর মাস সবকিছুকে ব্লক না করে।
কিছু ভেঙে গেলে (ভুল ফিল্টার, অনুমতি নেই, স্টোরেজ এরর), জবটি Failed হিসেবে মার্ক করে এবং ব্যবহারকারীকে একটি পরিষ্কার মেসেজ দেয়: "March invoices generate করা যায়নি। অনুগ্রহ করে retry করুন, অথবা Job ID 8F21 সঙ্গে সাপোর্টে যোগাযোগ করুন।" একটি retry একই ফিল্টার reuse করে যাতে ব্যবহারকারী আবার শুরু না করে দিতে হয়।
পরবর্তী ধাপ: এক্সপোর্টকে একটি বিল্ট-ইন ফিচার বানান, ক্রাইসিস নয়
দীর্ঘ মেয়াদে রপ্তানি টাইমআউট প্রতিরোধ করার দ্রুততম উপায় হলো এক্সপোর্টকে এক স্ট্যান্ডার্ড প্যাটার্ন হিসেবে তৈরি করা, ফায়ার-ড্রিল নয়।
একটি ডিফল্ট পদ্ধতি নিন এবং সব জায়গায় সেটি ব্যবহার করুন: async জব ব্যাকগ্রাউন্ডে ফাইল জেনারেট করে, তারপর ব্যবহারকারী ফাইল প্রস্তুত হলে ডাউনলোড পায়। এই সিদ্ধান্ত বেশিরভাগ "টেস্টে কাজ করেছিল" বিস্ময় সরিয়ে দেয়, কারণ ব্যবহারকারীর অনুরোধ পুরো ফাইলের জন্য অপেক্ষা করতে হবে না।
মানুষদের জন্য যা তারা আগে তৈরি করেছে তা খুঁজে পাওয়া সহজ করুন। একটি এক্সপোর্ট ইতিহাস পেজ (প্রতি ব্যবহারকারী, প্রতি ওয়ার্কস্পেস, বা প্রতি অ্যাকাউন্ট) পুনরায় এক্সপোর্ট কমায়, সাপোর্ট টিমকে সাহায্য করে "আমার ফাইল কোথায়?" প্রশ্নের উত্তর দিতে, এবং স্ট্যাটাস, এরর ও মেয়াদ শেষ হওয়ার সময় দেখানোর জন্য একটি স্বাভাবিক জায়গা দেয়।
যদি আপনি AppMaster-এ এই প্যাটার্ন তৈরি করে থাকেন, প্ল্যাটফর্মটি বাস্তব সোর্স কোড জেনারেট করে এবং ব্যাকএন্ড লজিক, ডাটাবেস মডেলিং, ও ওয়েব/মোবাইল UI এক জায়গায় সমর্থন করে। দ্রুত reliable async export jobs শিপ করতে চাওয়া দলগুলো প্রায়শই appmaster.io ব্যবহার করে job টেবিল, ব্যাকগ্রাউন্ড প্রসেস, এবং প্রগতি UI বানাতে—সবকিছু নিজে হাত দিয়ে বোনা ছাড়াই।
তারপর যা সত্যিই ব্যথা দেয় তা মাপুন। ধীর ডাটাবেস কুয়েরি, CSV জেনারেশনে সময়, এবং PDF রেন্ডার সময় ট্র্যাক করুন। আপনাকে নিখুঁত অবজার্ভেবিলিটি লাগবে না শুরু করার জন্য: এক্সপোর্ট প্রতি রক্ষিত সময় ও রো কাউন্ট লগ করলেই জানতে পারবেন কোন রিপোর্ট বা ফিল্টার কম্বিনেশন বাস্তবে সমস্যার কারণ।
রপ্তানিকে অন্য যেকোন প্রডাক্ট ফিচারের মতো আচরণ করুন: ধারাবাহিক, পরিমাপযোগ্য, এবং সাপোর্ট করা সহজ।
প্রশ্নোত্তর
একটি রপ্তানি তখন টাইমআউট হয় যখন কাজটি রিকোয়েস্ট-পাথের কোথাও নির্দিষ্ট সময়সীমার আগেই শেষ না হয়। সেই সীমা ব্রাউজার, একটি রিভার্স প্রোক্সি, আপনার অ্যাপ সার্ভার বা ডাটাবেস কানেকশন—যেকোনো স্থান থেকে আসতে পারে, তাই সমস্যা মাঝে মাঝে কাজ করা এবং মাঝে মাঝে ব্যর্থ হওয়া মনে হতে পারে যদিও মূল কারণ একই রকম ধীর কুয়েরি বা লোড।
সহজ "ক্লিক এবং ডাউনলোড" প্যাটার্ন ঠিক আছে যখন রপ্তানি বিশ্বস্তভাবে কয়েক সেকেন্ডে শেষ হয় এবং ডেটার আকার পূর্বানুমেয়। যদি রপ্তানি প্রায়ই 10–15 সেকেন্ডের বেশি সময় নেয়, বড় তারিখ-রেঞ্জ লাগে, ভারী গণনা থাকে, বা PDF জেনারেশন থাকে — তখন ব্রাউজার রিকোয়েস্ট খোলা রাখার বদলে async job ব্যবহার করুন।
প্রথমে একটি জব রেকর্ড তৈরি করুন, তারপর ভারী কাজ ব্যাকগ্রাউন্ডে চালান, শেষে ব্যবহারকারী ফাইল ডাউনলোড করতে পারে। AppMaster-এ সাধারণ সেটআপ হলো Data Designer-এ একটি ExportJob মডেল এবং ব্যাকএন্ড Business Process যা চলার সময় status, progress ফিল্ড আর স্টোর করা ফাইল রেফারেন্স আপডেট করে।
কাজের সময় নয়, বাস্তব কাজ ট্র্যাক করুন। বাস্তবসম্মত পদ্ধতি হলো step, processed_count, total_count (যদি জানা থাকে) এবং updated_at স্টোর করা, তারপর UI এগুলো পোল করে স্পষ্ট স্টেট দেখায় যাতে ব্যবহারকারীরা আটকে আছে বলে মনে না করে বারবার Export চাপে।
রপ্তানি অনুরোধ idempotent করুন এবং job রেকর্ডকে সত্যের উৎস বানান। ব্যবহারকারী যদি আবার ক্লিক করে, তাহলে চলমান একই জব দেখান (অথবা একই ফিল্টারের জন্য ডুপ্লিকেট ব্লক করুন) যাতে একই ব্যয়বহুল কাজ দুবার শুরু না হয়।
মেমরি স্থিতিশীল রাখতে ও প্রগতি চেকপয়েন্ট পেতে ডেটা চাঙ্ক করে পড়ুন ও লিখুন। একটি স্থির সোর্টিং ব্যবহার করুন (উদাহরণ: created_at তারপর id) যাতে লম্বা রপ্তানির সময় ডেটা বদলে গেলে রেকর্ড মিস বা ডুপ না হয়।
জব শুরু হলে একটি snapshot সময় নিন এবং শুধুমাত্র সেই টাইমস্ট্যম্প পর্যন্ত থাকা রেকর্ড এক্সপোর্ট করুন যাতে আউটপুট রান চলাকালীন "চলে" না যায়। কড়া কনসিস্টেন্সি চাইলে ডাটাবেসের সমর্থিত consistent read বা ট্রানজেকশন কৌশল ব্যবহার করুন, কিন্তু বেশিরভাগ ক্ষেত্রে স্পষ্ট snapshot নিয়মই পর্যাপ্ত।
স্ট্রিমিং উপকারী যখন আপনি ক্রমানুসারে আউটপুট তৈরি করে প্রথম বাইট দ্রুত পাঠাতে পারেন—বিশেষত বড় CSV-র জন্য। তবে এটি দীর্ঘ কুয়েরি যেগুলো প্রথম বাইটের আগে কয়েক মিনিট সময় নেয় সেভাবে ঠিক করবে না। তাই স্ট্রিমিংকে পেজিংয়ের সাথে মিলিয়ে ব্যবহার করুন যাতে নিয়মিতভাবে চাঙ্ক লিখে প্রক্রিয়া চলতে থাকে।
পঙক্তি হিসেবে লেখুন এবং প্রতিটি ফিল্ড যথাযথভাবে escape করুন যাতে ফাইল Excel-এ খুললেও কলাম নড়চড় না করে। consistent UTF-8 এনকোডিং ব্যবহার করুন, হেডার ও কলামের অর্ডার স্থির রাখুন, এবং per-row lookups এড়িয়ে এক কুয়েরিতে প্রয়োজনীয় সম্পর্কিত ডেটা লোড করুন।
PDF জেনারেশন সাধারণত CSV-এর তুলনায় ধীর কারণ এখানে লেআউট, ফণ্ট, ছবি ও পেজ ব্রেক লিঙ্ক থাকে—সুতরাং এটিকে ব্যাকগ্রাউন্ড কাজ হিসেবে ধরুন এবং স্পষ্ট সীমা রাখুন। টেমপ্লেট যত সহজ হবে তত দ্রুত ও নির্ভরযোগ্য হবে; বড় বা রিমোট ইমেজ রেন্ডারিং সময়ে ধীর করে দেয়।


