RxJS-এ Error Handling একটি গুরুত্বপূর্ণ দিক, যেহেতু অ্যাসিঙ্ক্রোনাস প্রোগ্রামিংয়ে অনেক সময় ত্রুটি (error) হতে পারে। RxJS-এ Error Handling Operators ব্যবহৃত হয় যাতে আমরা আমাদের Observable স্ট্রিমে ত্রুটির সাথে মোকাবিলা করতে পারি এবং তারপরে নির্দিষ্ট ধরণের রিয়্যাকশন প্রদান করতে পারি।
এখানে, আমরা কিছু গুরুত্বপূর্ণ Error Handling Operators সম্পর্কে আলোচনা করব, যেমন catchError, retry, retryWhen, এবং throwError।
1. catchError
catchError() অপারেটরটি Observable স্ট্রিমে কোনো ত্রুটি ঘটলে সেটি ক্যাচ করে এবং একটি নতুন Observable প্রদান করে। এটি ত্রুটি ঘটলে ডিফল্টভাবে স্ট্রিম বন্ধ না করে, বরং নতুন একটি স্ট্রিম শুরু করতে সাহায্য করে।
বৈশিষ্ট্য:
- Error handling: যখন Observable তে কোনো ত্রুটি ঘটে, তখন এটি সেটি ক্যাচ করে এবং একটি নতুন Observable বা ভ্যালু প্রদান করে।
- Stream continuation: এটি স্ট্রিমটি বন্ধ না করে, বরং নতুন Observable বা ভ্যালু দিয়ে স্ট্রিম অব্যাহত রাখে।
উদাহরণ:
import { of } from 'rxjs';
import { catchError } from 'rxjs/operators';
const observable = new Observable(observer => {
observer.next('Value 1');
observer.next('Value 2');
observer.error('Something went wrong!');
});
observable.pipe(
catchError(err => {
console.error('Error caught:', err);
return of('Recovered from error');
})
).subscribe(val => console.log(val));
আউটপুট:
Value 1
Value 2
Error caught: Something went wrong!
Recovered from error
এখানে, catchError ত্রুটির ঘটনা ক্যাচ করে এবং স্ট্রিমকে বন্ধ না করে "Recovered from error" মানটি পাঠায়।
2. retry
retry() অপারেটরটি একটি নির্দিষ্ট সংখ্যক বার Observable তে ত্রুটির পর পুনরায় চেষ্টা করতে সহায়তা করে। এটি একটি Observable পুনরায় সাবস্ক্রাইব করে যতবার না সফল ফলাফল পাওয়া যায়।
বৈশিষ্ট্য:
- Automatic retries: এটি একটি নির্দিষ্ট সংখ্যক বার Observable পুনরায় চেষ্টা করবে, ত্রুটি ঘটলে।
- Failure handling: যতবার ত্রুটি ঘটবে, ততবার পুনরায় চেষ্টা করা হবে যতক্ষণ না সফল ফলাফল পাওয়া যায়।
উদাহরণ:
import { of, throwError } from 'rxjs';
import { retry, map } from 'rxjs/operators';
const observable = new Observable(observer => {
console.log('Attempting...');
observer.error('Error occurred!');
});
observable.pipe(
retry(2) // ২ বার পুনরায় চেষ্টা করবে
).subscribe(
val => console.log(val),
err => console.error('Final Error:', err)
);
আউটপুট:
Attempting...
Attempting...
Attempting...
Final Error: Error occurred!
এখানে, retry(2) অপারেটরটি ত্রুটির পর ২ বার পুনরায় চেষ্টা করেছিল এবং সফল না হলে ত্রুটি নিয়ে সাবস্ক্রাইবারকে অবহিত করেছে।
3. retryWhen
retryWhen() অপারেটরটি একটি কমপ্লেক্স retry স্ট্রাটেজি তৈরি করতে ব্যবহৃত হয়। এটি একটি Observable কে ত্রুটির পর পুনরায় চেষ্টা করতে বলে, তবে পুনরায় চেষ্টা করার জন্য এটি একটি নতুন Observable নেয়, যা নির্দিষ্ট কন্ডিশন বা সময়সীমার ভিত্তিতে আবার চেষ্টা করবে।
বৈশিষ্ট্য:
- Custom retry logic: এটি retry করার জন্য কাস্টম লজিক ব্যবহার করে, যেমন নির্দিষ্ট সময় পর পুনরায় চেষ্টা করা।
- Dynamic retry conditions: retry করার সময় আপনি একটি নির্দিষ্ট শর্ত বা সময় নির্ধারণ করতে পারেন।
উদাহরণ:
import { of, throwError } from 'rxjs';
import { retryWhen, delay, take } from 'rxjs/operators';
const observable = new Observable(observer => {
console.log('Attempting...');
observer.error('Error occurred!');
});
observable.pipe(
retryWhen(errors => errors.pipe(
delay(1000), // 1 সেকেন্ড অপেক্ষা করবে
take(3) // ৩ বার চেষ্টা করবে
))
).subscribe(
val => console.log(val),
err => console.log('Final Error:', err)
);
আউটপুট:
Attempting...
Attempting...
Attempting...
Final Error: Error occurred!
এখানে, retryWhen ১ সেকেন্ড পর ৩ বার পুনরায় চেষ্টা করবে এবং তারপর স্ট্রিমে ত্রুটি পাঠাবে।
4. throwError
throwError() অপারেটরটি একটি Observable এর মধ্যে ত্রুটি প্রদান করতে ব্যবহৃত হয়। আপনি যখন নিজে থেকে একটি ত্রুটি চান, তখন আপনি এই অপারেটরটি ব্যবহার করতে পারেন।
বৈশিষ্ট্য:
- Manually throwing errors: আপনি একটি নির্দিষ্ট ত্রুটি বা কাস্টম ত্রুটি তৈরি করতে পারেন এবং এটি Observable স্ট্রিমে পুশ করতে পারেন।
- Observable error propagation: এই ত্রুটি Observable স্ট্রিমে একত্রিত হবে এবং অন্যান্য অপারেটর বা সাবস্ক্রাইবারের কাছে পাঠানো হবে।
উদাহরণ:
import { throwError } from 'rxjs';
const observable = throwError('Custom error');
observable.subscribe({
next: (val) => console.log(val),
error: (err) => console.error('Error caught:', err)
});
আউটপুট:
Error caught: Custom error
এখানে, throwError একটি কাস্টম ত্রুটি পাঠাচ্ছে যা সাবস্ক্রাইবার দ্বারা ক্যাচ করা হচ্ছে।
সারাংশ
RxJS-এ Error Handling Operators ব্যবহার করে আপনি অ্যাসিঙ্ক্রোনাস ডেটার মধ্যে ত্রুটির ক্ষেত্রে আরও নিয়ন্ত্রণ পেতে পারেন। এই অপারেটরগুলো মূলত ডেটা স্ট্রিমে ত্রুটি ঘটলে প্রোগ্রামটিকে স্থির না করে, তার পরিবর্তে নির্দিষ্ট শর্তে বা পুনরায় চেষ্টা করার জন্য একটি উপায় প্রদান করে।
- catchError: ত্রুটি ক্যাচ করে নতুন Observable দিয়ে স্ট্রিম চালু রাখে।
- retry: নির্দিষ্ট সংখ্যক বার পুনরায় চেষ্টা করে।
- retryWhen: কাস্টম retry লজিক অনুযায়ী পুনরায় চেষ্টা করে।
- throwError: কাস্টম ত্রুটি সৃষ্টি করে।
এই অপারেটরগুলো ব্যবহারের মাধ্যমে আপনি অ্যাসিঙ্ক্রোনাস অ্যাপ্লিকেশনগুলোতে ত্রুটির মোকাবেলা করতে আরও সহজ এবং কার্যকরী উপায় পেতে পারেন।
RxJS (Reactive Extensions for JavaScript) অ্যাসিঙ্ক্রোনাস ডেটা স্ট্রিম এবং ইভেন্ট হ্যান্ডলিংয়ের জন্য একটি শক্তিশালী লাইব্রেরি। অ্যাসিঙ্ক্রোনাস কাজের মধ্যে অনেক সময় ত্রুটি (error) ঘটতে পারে, এবং সেগুলির সঠিকভাবে হ্যান্ডল করা প্রোগ্রামের স্থিতিশীলতা নিশ্চিত করতে গুরুত্বপূর্ণ। catchError() এবং retry() দুটি জনপ্রিয় RxJS অপারেটর, যেগুলি ত্রুটি হ্যান্ডলিংয়ের জন্য ব্যবহৃত হয় এবং ডেটা স্ট্রিমে ত্রুটির ক্ষেত্রে পুনরায় চেষ্টা (retry) করতে সহায়তা করে।
এই দুটি অপারেটর কীভাবে কাজ করে এবং কীভাবে সেগুলি error handling এর জন্য ব্যবহার করা যায়, তা এখানে আলোচনা করা হবে।
1. catchError() অপারেটর
catchError() অপারেটরটি ব্যবহৃত হয় যখন কোনো Observable এর মধ্যে ত্রুটি (error) ঘটে এবং ত্রুটি হ্যান্ডলিংয়ের জন্য fallback Observable প্রদান করতে হয়। এটি মূল Observable থেকে error ধরা এবং সেই error এর পরিবর্তে একটি নতুন Observable বা fallback ভ্যালু রিটার্ন করার জন্য ব্যবহার করা হয়।
বৈশিষ্ট্য:
- Error Handling: ত্রুটি ঘটলে তার পরিবর্তে fallback Observable প্রদান করা হয়।
- Error Recovery: স্ট্রিমের ত্রুটি ধরা এবং তাকে handle করার জন্য একটি অন্য Observable প্রদান করা যায়।
উদাহরণ:
import { of } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { throwError } from 'rxjs';
const observable = new Observable((observer) => {
observer.next('First value');
observer.next('Second value');
observer.error('An error occurred'); // Error occurs here
});
observable.pipe(
catchError((error) => {
console.log('Caught error:', error);
return of('Fallback value'); // Return a fallback value in case of error
})
).subscribe({
next: (value) => console.log(value),
error: (err) => console.log('Error:', err),
complete: () => console.log('Completed'),
});
আউটপুট:
Received: First value
Received: Second value
Caught error: An error occurred
Received: Fallback value
Completed
এখানে, catchError() ত্রুটি ধরেছে এবং একটি fallback value (Fallback value) পাঠিয়েছে, এবং ত্রুটি ছাড়া স্ট্রিম সম্পন্ন হয়েছে।
2. retry() অপারেটর
retry() অপারেটরটি যখন কোনো Observable ত্রুটি (error) দেয়, তখন এটি পুনরায় সেই Observable চালানোর চেষ্টা করে। আপনি কতবার retry করতে চান, তা নির্ধারণ করতে পারেন। সাধারণত এটি সেগুলির জন্য ব্যবহৃত হয় যেখানে ত্রুটি অস্থায়ী (temporary) হয় এবং পুনরায় চেষ্টা করা সম্ভব।
বৈশিষ্ট্য:
- Retry Mechanism: ত্রুটি ঘটলে নির্দিষ্ট সংখ্যক বার পুনরায় চেষ্টা করা হয়।
- Error Recovery: এটি ত্রুটির পুনরায় চেষ্টা করার জন্য একটি retry লজিক তৈরি করতে সাহায্য করে।
উদাহরণ:
import { of, throwError } from 'rxjs';
import { retry, catchError } from 'rxjs/operators';
const observable = new Observable((observer) => {
observer.next('First value');
observer.next('Second value');
observer.error('An error occurred'); // Error occurs here
});
observable.pipe(
retry(2), // Retry up to 2 times
catchError((error) => {
console.log('Caught error after retries:', error);
return of('Fallback value'); // Return a fallback value if retries fail
})
).subscribe({
next: (value) => console.log(value),
error: (err) => console.log('Error:', err),
complete: () => console.log('Completed'),
});
আউটপুট:
Received: First value
Received: Second value
Caught error after retries: An error occurred
Received: Fallback value
Completed
এখানে, retry(2) অপারেটরটি ত্রুটির পরে ২ বার পুনরায় চেষ্টা করেছে। পুনরায় চেষ্টা করার পরেও ত্রুটি ঘটলে catchError() ফালব্যাক ভ্যালু পাঠিয়েছে।
3. retryWhen() অপারেটর
retryWhen() অপারেটরটি আরও কাস্টম retry লজিক তৈরি করতে ব্যবহৃত হয়। এটি error এর উপর ভিত্তি করে পুনরায় চেষ্টা করার কৌশল নির্ধারণ করতে সহায়তা করে। আপনি এটি দিয়ে পুনরায় চেষ্টা করার জন্য একটি কাস্টম Observable প্রদান করতে পারেন, যা ত্রুটি ঘটলে retry করতে সাহায্য করে।
বৈশিষ্ট্য:
- Custom Retry Logic: আপনি retry করার জন্য একটি কাস্টম Observable ব্যবহার করতে পারেন।
- Delay Mechanism: আপনি retry এর মধ্যে বিলম্ব (delay) যুক্ত করতে পারেন।
উদাহরণ:
import { throwError, of } from 'rxjs';
import { retryWhen, delay, mergeMap } from 'rxjs/operators';
const observable = throwError('Temporary network issue');
observable.pipe(
retryWhen(errors =>
errors.pipe(
mergeMap((error, index) => {
if (index < 3) {
console.log(`Retrying... attempt #${index + 1}`);
return of(error).pipe(delay(1000)); // Retry after 1 second
}
return throwError('Retries failed'); // After 3 retries, throw error
})
)
)
).subscribe({
next: (value) => console.log(value),
error: (err) => console.log('Error:', err),
complete: () => console.log('Completed'),
});
আউটপুট:
Retrying... attempt #1
Retrying... attempt #2
Error: Retries failed
এখানে, retryWhen() এর মাধ্যমে ত্রুটি হওয়ার পর ১ সেকেন্ড পর পর পুনরায় চেষ্টা করা হচ্ছে এবং ৩ বার চেষ্টা করার পরেও ত্রুটি হলে তা ছুড়ে দেয়া হচ্ছে।
4. throwError() - Error সৃষ্টি করা
throwError() অপারেটরটি ব্যবহৃত হয় একটি কৃত্রিম ত্রুটি তৈরি করার জন্য, যাতে আপনি manually error throw করতে পারেন।
উদাহরণ:
import { throwError } from 'rxjs';
const error$ = throwError('An intentional error occurred');
error$.subscribe({
next: (value) => console.log('Received:', value),
error: (err) => console.log('Caught error:', err),
complete: () => console.log('Completed'),
});
আউটপুট:
Caught error: An intentional error occurred
এখানে, throwError() দ্বারা একটি কৃত্রিম error তৈরি করা হয়েছে, যা subscribe এ error হ্যান্ডলিংয়ের মাধ্যমে ধরা পড়েছে।
সারাংশ
RxJS তে error handling এর জন্য catchError(), retry(), retryWhen(), এবং throwError() ব্যবহার করা হয়, যেগুলি ত্রুটি সমাধান করতে এবং অ্যাসিঙ্ক্রোনাস স্ট্রিমে ত্রুটির ঘটনা সামলাতে সহায়তা করে।
- catchError() ত্রুটি হ্যান্ডলিংয়ের জন্য একটি fallback Observable রিটার্ন করে।
- retry() ত্রুটির পর নির্দিষ্ট সংখ্যক বার পুনরায় চেষ্টা করে।
- retryWhen() কাস্টম retry লজিক তৈরি করার জন্য ব্যবহার করা হয়।
- throwError() কৃত্রিম error তৈরি করতে ব্যবহৃত হয়।
এই অপারেটরগুলির মাধ্যমে আপনি ত্রুটি হ্যান্ডলিংকে আরও কার্যকরী এবং মেইন্টেনেবল করতে পারবেন, বিশেষত যখন আপনি অ্যাসিঙ্ক্রোনাস স্ট্রিমের সাথে কাজ করছেন।
RxJS (Reactive Extensions for JavaScript) একটি শক্তিশালী লাইব্রেরি যা অ্যাসিঙ্ক্রোনাস ডেটা স্ট্রিম এবং ইভেন্টগুলোকে কার্যকরভাবে পরিচালনা করতে সহায়ক। অনেক সময় আমাদের API কল বা অন্যান্য অ্যাসিঙ্ক্রোনাস কাজগুলিতে retry করার প্রয়োজন হয়, যেমন যখন কোনো ইরর (error) ঘটে তখন কিছু নির্দিষ্ট শর্তে পুনরায় চেষ্টা করতে হবে। এই কাজটি retryWhen() মেথড ব্যবহার করে Custom Retry Logic তৈরি করা যায়।
retryWhen() অপারেটরটি একটি Observable প্রদান করে, যা একটি ত্রুটি (error) হলে পুনরায় চেষ্টা করার কৌশল নির্ধারণ করতে সহায়তা করে।
retryWhen() কী?
retryWhen() একটি RxJS অপারেটর যা সাবস্ক্রাইবারের সাবস্ক্রিপশনকে পুনরায় শুরু করার জন্য custom retry strategy নির্ধারণ করতে ব্যবহৃত হয়। এটি একটি Observable গ্রহণ করে এবং যদি ত্রুটি ঘটে তবে সেই Observable থেকে পুনরায় চেষ্টা করার নির্দেশনা দেয়। retryWhen() সাধারণত একটি Observable প্রদান করে যা আবার ট্রাই করার জন্য পুনরায় চেষ্টার সময়সূচী এবং কৌশল নির্ধারণ করে।
retryWhen() এর ব্যবহার
retryWhen() অপারেটরের সাথে একটি কাস্টম retry strategy তৈরি করা যায়, যেখানে ইররের ঘটনার পরে কীভাবে আবার রিকোয়েস্ট করা হবে তা নির্ধারণ করা হয়। সাধারণত এটি একটি observable যা ত্রুটি ঘটলে পুনরায় চেষ্টা করার জন্য নির্দিষ্ট সময় বা কন্ডিশন নির্ধারণ করে।
উদাহরণ:
ধরা যাক, আমরা একটি HTTP রিকোয়েস্ট পাঠাচ্ছি, এবং যদি প্রথমে ত্রুটি ঘটে, তবে আমরা কাস্টম রিট্রি স্ট্র্যাটেজি ব্যবহার করে আবার চেষ্টা করতে চাই।
import { of } from 'rxjs';
import { retryWhen, delay, take, mergeMap } from 'rxjs/operators';
// একটি কাস্টম Observable যা আমাদের সিমুলেটেড API কলের মতো কাজ করবে
function makeApiCall() {
return Math.random() > 0.5 ? of('Success') : throw new Error('API Call Failed');
}
// Retry Logic
const observable = makeApiCall().pipe(
retryWhen(errors =>
errors.pipe(
mergeMap((error, index) => {
if (index < 3) {
console.log(`Attempt ${index + 1}: Retrying after error - ${error.message}`);
return of(error).pipe(delay(1000)); // ১ সেকেন্ড পর পুনরায় চেষ্টা করবে
}
return throw error; // ৩ বার চেষ্টা করার পরও ইরর হলে ত্রুটি ছুড়ে দিবে
})
)
)
);
observable.subscribe({
next: result => console.log(result),
error: err => console.log('Final Error:', err)
});
কোড বিশ্লেষণ:
makeApiCall()ফাংশন একটি র্যান্ডম ৫০% সাকসেস রেটের সাথে একটি API কল সিমুলেট করে। যদিMath.random()> 0.5 হয় তবে এটি সফল হয়, অন্যথায় এটি একটি ত্রুটি ছুড়ে দেয়।retryWhen()অপারেটরটি ত্রুটি ঘটলে পুনরায় চেষ্টা করার জন্য একটি কাস্টম লজিক নিয়ন্ত্রণ করে। এখানে আমরা ত্রুটি হলে প্রতি ১ সেকেন্ড পর তিনবার চেষ্টা করার নির্দেশ দিচ্ছি।- mergeMap অপারেটরটি ব্যবহৃত হয়েছে, যা পুনরায় চেষ্টা করার জন্য নির্দিষ্ট সময় সেট করে এবং চেষ্টা সংখ্যা অনুযায়ী সিদ্ধান্ত নেয়।
throw errorব্যবহার করা হয়েছে যখন ৩ বার চেষ্টা করার পরও সফল না হয়।
retryWhen() এর মাধ্যমে বিভিন্ন ধরনের Retry Logic
retryWhen() এর মাধ্যমে বিভিন্ন কৌশলে কাস্টম retry logic তৈরি করা যায়। কিছু সাধারণ কৌশল হলো:
- Fixed Interval Retry: প্রতিবার ইররের পরে নির্দিষ্ট সময়ের ব্যবধানে পুনরায় চেষ্টা করা।
- Exponential Backoff: একের পর এক রিট্রাইয়ের জন্য সময় বাড়িয়ে নেওয়া।
- Max Retry Attempts: নির্দিষ্ট সংখ্যক চেষ্টা করার পর পুনরায় চেষ্টা বন্ধ করা।
Exponential Backoff Example:
import { throwError } from 'rxjs';
import { retryWhen, delay, take, mergeMap } from 'rxjs/operators';
function makeApiCall() {
return Math.random() > 0.5 ? of('Success') : throwError(new Error('API Call Failed'));
}
const observable = makeApiCall().pipe(
retryWhen(errors =>
errors.pipe(
mergeMap((error, index) => {
if (index < 5) {
const delayTime = Math.pow(2, index) * 1000; // Exponential backoff (2^index)
console.log(`Attempt ${index + 1}: Retrying after ${delayTime / 1000} seconds`);
return of(error).pipe(delay(delayTime));
}
return throwError(error); // ৫ বার চেষ্টা করার পরও ইরর হলে ত্রুটি ছুড়ে দিবে
})
)
)
);
observable.subscribe({
next: result => console.log(result),
error: err => console.log('Final Error:', err)
});
এখানে, delayTime প্রত্যেক ব্যর্থতার পরে দ্বিগুণ বাড়ানো হয়, অর্থাৎ প্রথম চেষ্টা ১ সেকেন্ড, দ্বিতীয় চেষ্টা ২ সেকেন্ড, তৃতীয় চেষ্টা ৪ সেকেন্ড ইত্যাদি।
সারাংশ
retryWhen() RxJS এর একটি শক্তিশালী অপারেটর, যা কাস্টম retry লজিক তৈরি করতে ব্যবহৃত হয়। এটি ত্রুটি (error) হলে পুনরায় চেষ্টা করার জন্য কাস্টম স্ট্র্যাটেজি গ্রহণ করতে সাহায্য করে। আপনি mergeMap এবং delay সহ অন্যান্য অপারেটর ব্যবহার করে পুনরায় চেষ্টা করার সময় নির্ধারণ এবং retry কৌশল তৈরি করতে পারেন, যেমন fixed interval, exponential backoff, বা max retry attempts। এই কাস্টম retry লজিক আপনার অ্যাপ্লিকেশনে উন্নত ত্রুটি পরিচালনা এবং পুনরুদ্ধারের জন্য কার্যকরী।
RxJS (Reactive Extensions for JavaScript) অ্যাসিঙ্ক্রোনাস এবং ইভেন্ট-ভিত্তিক অ্যাপ্লিকেশনগুলির জন্য একটি শক্তিশালী লাইব্রেরি। তবে, যেকোন অ্যাসিঙ্ক্রোনাস অপারেশন বা স্ট্রিমের সময় Error Handling একটি গুরুত্বপূর্ণ ভূমিকা পালন করে, কারণ ডেটার প্রতি নিয়ন্ত্রণ এবং প্রসেসিংয়ের সময় বিভিন্ন ধরনের সমস্যা বা ত্রুটি (error) হতে পারে। RxJS-এ error handling করতে কয়েকটি প্র্যাকটিস রয়েছে, যেগুলি অ্যাপ্লিকেশনকে আরও স্থিতিশীল এবং ব্যতিক্রমী পরিস্থিতির জন্য প্রস্তুত রাখে।
এখানে আমরা আলোচনা করবো RxJS তে Error Handling এর কিছু Best Practices।
1. catchError() ব্যবহার করা
catchError() অপারেটরটি যখন কোন error ঘটবে, তখন সেই error-টি হ্যান্ডেল করার জন্য ব্যবহার করা হয়। এটি একটি observable রিটার্ন করে, যা error এর পরে কোনো বিকল্প Observable প্রদান করে।
ব্যবহার:
- Error Handling:
catchError()ব্যবহার করলে আপনি error হওয়ার পর fallback অথবা alternative Observable ব্যবহার করতে পারবেন।
উদাহরণ:
import { of } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { throwError } from 'rxjs';
const observable = throwError('Something went wrong');
observable.pipe(
catchError(err => {
console.error('Caught error:', err);
return of('Fallback Value'); // Fallback value
})
).subscribe(
data => console.log(data),
error => console.error('Error:', error)
);
ব্যাখ্যা:
- যখন
observableএ throwError() থেকে error হবে, তখনcatchError()সেই error ধরবে এবং একটি fallback Observable (of('Fallback Value')) রিটার্ন করবে। - এখানে, error হ্যান্ডলিংয়ের মাধ্যমে স্ট্রিম অব্যাহত থাকবে, এবং সাবস্ক্রাইবারে fallback value পৌঁছাবে।
2. retry() এবং retryWhen() ব্যবহার করা
retry() এবং retryWhen() অপারেটরগুলি retrying অথবা পুনরায় চেষ্টা করার জন্য ব্যবহৃত হয়। এটি error ঘটলে, নির্দিষ্ট সংখ্যক বার পুনরায় try করার সুযোগ দেয়।
ব্যবহার:
- Retry Mechanism: যখন কোন অস্থায়ী সমস্যা ঘটে (যেমন নেটওয়ার্ক সমস্যা), তখন retry অপারেটর ব্যবহার করা যায় যাতে স্ট্রিম পুনরায় সফলভাবে সম্পন্ন হয়।
উদাহরণ: retry()
import { of, throwError } from 'rxjs';
import { retry } from 'rxjs/operators';
const observable = throwError('Temporary network issue');
observable.pipe(
retry(2) // Retry 2 times
).subscribe(
data => console.log(data),
error => console.error('Error:', error)
);
ব্যাখ্যা:
retry(2)ব্যবহার করে, প্রথম error হওয়ার পর ২ বার পুনরায় চেষ্টা করা হবে। এর পরে error হলে, তা সাবস্ক্রাইবারের কাছে পাঠানো হবে।
উদাহরণ: retryWhen()
import { of, throwError } from 'rxjs';
import { retryWhen, delay, take } from 'rxjs/operators';
const observable = throwError('Temporary network issue');
observable.pipe(
retryWhen(errors =>
errors.pipe(
delay(1000), // 1 second delay
take(3) // Retry 3 times
)
)
).subscribe(
data => console.log(data),
error => console.error('Error:', error)
);
ব্যাখ্যা:
retryWhen()ব্যবহার করে, error হলে, retry করতে 1 সেকেন্ডের delay দেওয়া হয় এবং সর্বোচ্চ ৩ বার retry করার পরে error পাঠানো হয়।
3. finalize() ব্যবহার করা
finalize() অপারেটরটি স্ট্রিমের শেষ হওয়া (complete বা error হওয়ার পর) পরে কিছু কাজ সম্পন্ন করার জন্য ব্যবহার করা হয়। এটি কোনো clean-up বা log করার কাজে ব্যবহার করা যেতে পারে।
ব্যবহার:
- Resource Cleanup: স্ট্রিম বন্ধ হওয়ার পর যেমন error বা completion, তখন কিছু ক্লিন-আপ কোড বা লগিং কাজ করতে সাহায্য করে।
উদাহরণ:
import { of } from 'rxjs';
import { finalize } from 'rxjs/operators';
const observable = of('Data');
observable.pipe(
finalize(() => {
console.log('Stream has completed or errored');
})
).subscribe(
data => console.log(data),
error => console.error('Error:', error)
);
ব্যাখ্যা:
- স্ট্রিম শেষ হলে,
finalize()কল হবে এবং এটি লগ করবে "Stream has completed or errored"। এই অপারেটরটি error বা completion পরেও ক্লিন-আপ বা লগিং করার জন্য উপকারী।
4. throwError() এবং catchError() এর সঠিক ব্যবহার
throwError() অপারেটরটি ব্যবহার করে আপনি একটি error manually throw করতে পারেন। এটি সাধারণত error generation এবং propagation এর জন্য ব্যবহৃত হয়।
উদাহরণ: throwError() + catchError()
import { throwError, of } from 'rxjs';
import { catchError } from 'rxjs/operators';
const observable = throwError('Something went wrong');
observable.pipe(
catchError(err => {
console.error('Error caught:', err);
return of('Recovered with fallback data');
})
).subscribe(
data => console.log(data),
error => console.error('Final Error:', error)
);
ব্যাখ্যা:
throwError()দ্বারা error ঘটানোর পর,catchError()সেই error হ্যান্ডেল করে একটি fallback Observable রিটার্ন করে এবং সাবস্ক্রাইবারে fallback ডেটা পাঠানো হয়।
5. onErrorResumeNext() ব্যবহার করা
onErrorResumeNext() অপারেটরটি স্ট্রিমে error ঘটলে, error না তুলে পরবর্তী Observable গুলো চালু রাখে। এটি error ঘটলে স্ট্রিমের অব্যাহত রাখতে সহায়ক।
উদাহরণ:
import { of, throwError } from 'rxjs';
import { onErrorResumeNext } from 'rxjs/operators';
const observable = throwError('Error occurred').pipe(
onErrorResumeNext(of('Next observable'))
);
observable.subscribe(
data => console.log(data),
error => console.error('Error:', error)
);
ব্যাখ্যা:
onErrorResumeNext()error ঘটলেও পরবর্তী Observable (of('Next observable')) চালু থাকবে এবং সাবস্ক্রাইবারকে পাঠানো হবে।
6. User-Friendly Error Messages
User-friendly error messages তৈরি করা খুবই গুরুত্বপূর্ণ। RxJS এ যখন error ফেলে, তখন তা সাধারণত raw error message হিসেবে আসে। তবে, আপনি catchError() এর মাধ্যমে আরও ব্যবহারকারী-বান্ধব ত্রুটি বার্তা প্রদান করতে পারেন।
উদাহরণ:
import { of } from 'rxjs';
import { catchError } from 'rxjs/operators';
const observable = of('Data');
observable.pipe(
catchError(error => {
return of('Oops! Something went wrong. Please try again later.');
})
).subscribe(data => {
console.log(data);
});
ব্যাখ্যা:
- catchError() ত্রুটি হলে, এটি ব্যবহারকারী-বান্ধব একটি বার্তা রিটার্ন করবে, যা ব্যবহারকারীর কাছে বুঝতে সহজ হবে।
সারাংশ
RxJS তে error handling এর জন্য কিছু গুরুত্বপূর্ণ best practices হল:
- catchError() ব্যবহার করে ত্রুটি হ্যান্ডলিং করা এবং fallback Observable প্রদান করা।
- retry() এবং retryWhen() ব্যবহার করে নির্দিষ্ট সংখ্যক retry করা।
- finalize() ব্যবহার করে স্ট্রিম শেষ হওয়ার পরে কিছু কাজ করা (যেমন ক্লিন-আপ বা লগিং)।
- throwError() দিয়ে error manually throw করা এবং তা হ্যান্ডল করা।
- onErrorResumeNext() দিয়ে error ঘটলেও পরবর্তী Observable চালু রাখা।
- ব্যবহারকারী-বান্ধব error messages প্রদান করা।
এই প্র্যাকটিসগুলো RxJS-এ error handling এর কার্যকারিতা বাড়ায় এবং আপনার অ্যাপ্লিকেশনকে আরও স্থিতিশীল করে তোলে।
RxJS-এ Error Handling একটি গুরুত্বপূর্ণ অংশ, বিশেষত যখন আপনি অ্যাসিঙ্ক্রোনাস প্রোগ্রামিং করছেন এবং বিভিন্ন স্ট্রিম বা অপারেশনগুলিতে ত্রুটি (error) ঘটতে পারে। RxJS এর বিভিন্ন অপারেটর রয়েছে যা error handling সহজ এবং কার্যকরী করতে সাহায্য করে। যখন অ্যাসিঙ্ক্রোনাস অপারেশনগুলোতে ত্রুটি ঘটে, তখন আপনি catchError, retry, retryWhen ইত্যাদি অপারেটর ব্যবহার করে সেই ত্রুটির মোকাবিলা করতে পারেন।
এখানে, আমরা দেখব কিভাবে error handling অপারেটরগুলো RxJS স্ট্রিমে প্রয়োগ করা যায়।
1. catchError() অপারেটর
catchError() অপারেটরটি ত্রুটি ঘটলে তাকে ধরা এবং তা সমাধান বা পুনরায় চেষ্টা করার জন্য ব্যবহৃত হয়। এটি একটি fallback Observable প্রদান করতে সাহায্য করে যখন মূল Observable-এ কোনো ত্রুটি ঘটে।
বৈশিষ্ট্য:
- Fallback Observable: যখন কোনো ত্রুটি ঘটে, তখন আপনি একটি নতুন Observable ফিরিয়ে দিতে পারেন।
- Error Recovery: এটি মূল স্ট্রিমের ত্রুটিকে "ধরে" এবং আপনাকে ত্রুটির স্থলে অন্য একটি Observable পাঠানোর সুযোগ দেয়।
উদাহরণ:
import { of } from 'rxjs';
import { catchError } from 'rxjs/operators';
const source$ = new Observable((observer) => {
observer.next('First value');
observer.next('Second value');
observer.error('An error occurred'); // Error occurs here
});
source$.pipe(
catchError((error) => {
console.log('Caught error:', error);
return of('Fallback value'); // Return a fallback value in case of error
})
).subscribe({
next: (value) => console.log('Received:', value),
error: (err) => console.log('Error:', err),
complete: () => console.log('Completed'),
});
আউটপুট:
Received: First value
Received: Second value
Caught error: An error occurred
Received: Fallback value
Completed
এখানে, যখন ত্রুটি ঘটলো, তখন catchError() fallback value 'Fallback value' পাঠিয়েছে, এবং ত্রুটি সমাধান হয়েছে।
2. retry() অপারেটর
retry() অপারেটরটি ত্রুটি ঘটলে মূল Observable কে পুনরায় চেষ্টা (retry) করতে বলে। আপনি কতবার পুনরায় চেষ্টা করতে চান, তা নির্ধারণ করতে পারেন।
বৈশিষ্ট:
- Retry Limit: নির্দিষ্ট সংখ্যক বার পুনরায় চেষ্টা করতে পারে।
- Error Recovery: যদি Observable ত্রুটি না দেয়, তবে পুনরায় চেষ্টা করা হয় যতক্ষণ না সেটি সফল না হয়।
উদাহরণ:
import { of, throwError } from 'rxjs';
import { retry, catchError } from 'rxjs/operators';
const source$ = new Observable((observer) => {
observer.next('First value');
observer.next('Second value');
observer.error('An error occurred'); // Error occurs here
});
source$.pipe(
retry(2), // Retry up to 2 times
catchError((error) => {
console.log('Caught error after retries:', error);
return of('Fallback value'); // Return a fallback value if retries fail
})
).subscribe({
next: (value) => console.log('Received:', value),
error: (err) => console.log('Error:', err),
complete: () => console.log('Completed'),
});
আউটপুট:
Received: First value
Received: Second value
Caught error after retries: An error occurred
Received: Fallback value
Completed
এখানে, retry(2) অপারেটরটি ত্রুটির পরে ২ বার পুনরায় চেষ্টা করেছে, কিন্তু ত্রুটি অব্যাহত থাকায় catchError() ফ্লেকব্যাক ভ্যালু পাঠিয়েছে।
3. retryWhen() অপারেটর
retryWhen() অপারেটরটি একটু ভিন্নভাবে কাজ করে। এটি যখন ত্রুটি ঘটে, তখন নির্দিষ্ট শর্তে Observable-কে পুনরায় চেষ্টা (retry) করার জন্য ব্যবহৃত হয়। আপনি একটি Notifiable Observable প্রদান করতে পারেন, যা শর্ত পূর্ণ হলে পুনরায় চেষ্টা করবে।
বৈশিষ্ট:
- Custom Retry Logic: এটি আপনাকে কাস্টম লজিক তৈরি করতে সাহায্য করে, যেমন একটি বিলম্ব (delay) বা পুনরায় চেষ্টা করার শর্ত।
উদাহরণ:
import { of, throwError } from 'rxjs';
import { retryWhen, delay, mergeMap } from 'rxjs/operators';
const source$ = new Observable((observer) => {
observer.next('First value');
observer.next('Second value');
observer.error('An error occurred'); // Error occurs here
});
source$.pipe(
retryWhen(errors =>
errors.pipe(
mergeMap((error, index) => {
if (index < 2) {
console.log(`Retrying... attempt #${index + 1}`);
return of(error).pipe(delay(1000)); // Retry after 1 second
}
return throwError('Retries failed'); // After 2 retries, throw error
})
)
)
).subscribe({
next: (value) => console.log('Received:', value),
error: (err) => console.log('Error:', err),
complete: () => console.log('Completed'),
});
আউটপুট:
Retrying... attempt #1
Retrying... attempt #2
Error: Retries failed
এখানে, retryWhen() ত্রুটির পরে পুনরায় চেষ্টা করেছে এবং delay(1000) দিয়ে ১ সেকেন্ড পর পর পুনরায় চেষ্টা করেছে। ২ বার চেষ্টা করার পরে, ত্রুটি ফিরে এসেছে।
4. throwError() - Error সৃষ্টি করা
throwError() অপারেটরটি একটি নতুন Observable তৈরি করে যা একটি ত্রুটি ছুড়ে দেয়। এটি তখন ব্যবহৃত হয় যখন আপনি manual error throwing করতে চান।
উদাহরণ:
import { throwError } from 'rxjs';
const error$ = throwError('An intentional error occurred');
error$.subscribe({
next: (value) => console.log('Received:', value),
error: (err) => console.log('Caught error:', err),
complete: () => console.log('Completed'),
});
আউটপুট:
Caught error: An intentional error occurred
এখানে, throwError() একটি কৃত্রিম ত্রুটি তৈরি করেছে, এবং সাবস্ক্রাইবার ত্রুটি ধরেছে।
সারাংশ
RxJS-এ error handling এর জন্য বিভিন্ন অপারেটর ব্যবহার করা যায়, যা অ্যাসিঙ্ক্রোনাস স্ট্রিমে ত্রুটি পরিচালনা করার ক্ষেত্রে সহায়ক। গুরুত্বপূর্ণ অপারেটরগুলো হলো:
- catchError(): ত্রুটি ঘটলে তাকে ধরতে এবং একটি নতুন Observable বা fallback value প্রদান করতে ব্যবহৃত হয়।
- retry(): ত্রুটি ঘটলে নির্দিষ্ট সংখ্যক বার পুনরায় চেষ্টা করে।
- retryWhen(): কাস্টম পুনরায় চেষ্টা করার লজিক তৈরির জন্য ব্যবহৃত হয়।
- throwError(): কৃত্রিম ত্রুটি তৈরি করতে ব্যবহৃত হয়।
এই অপারেটরগুলির মাধ্যমে আপনি রিয়্যাক্টিভ প্রোগ্রামিংয়ে ত্রুটির সমস্যা ম্যানেজ করে ডেটা প্রক্রিয়াকরণকে আরও শক্তিশালী এবং নির্ভরযোগ্য করতে পারেন।
Read more