فال بیک پیٹرن: مائیکرو سروسز میں خوبصورت انحطاط کو ڈیزائن کرنا

فال بیک پیٹرن: مائیکرو سروسز میں خوبصورت انحطاط کو ڈیزائن کرنا

مائیکرو سروسز فن تعمیر میں، خدمات تقسیم شدہ نیٹ ورک کالوں کا ایک ویب بناتی ہیں۔ اگرچہ یہ ٹیموں کو آزادانہ طور پر خدمات بنانے اور اسکیل کرنے کی اجازت دیتا ہے، اس کا مطلب یہ بھی ہے کہ آپ کے سسٹم کی مجموعی اعتبار صرف اس کے کمزور ترین لنک کی طرح مضبوط ہے۔ اگر کوئی اہم سروس بند ہو جاتی ہے یا غیر جوابدہ ہو جاتی ہے، تو یہ ایک جھرنے والی ناکامی کو متحرک کر سکتی ہے جو پوری ایپلیکیشن میں خلل ڈالتی ہے۔

ایک عام “500 اندرونی سرور کی خرابی” یا ایک خالی صفحہ صارفین کو واپس کرنا جب ایک واحد انحصار ناکام ہوجاتا ہے تو صارف کا تجربہ خراب ہوتا ہے۔ اس کے بجائے، جب چیزیں غلط ہو جاتی ہیں تو لچکدار نظام خوبصورتی سے انحطاط کے لیے بنائے جاتے ہیں۔

یہ وہ جگہ ہے جہاں فال بیک پیٹرن آتا ہے۔ پرائمری سروس کال کے ناکام ہونے پر عملدرآمد کے ایک محفوظ، متبادل راستے کی وضاحت کرکے، آپ اپنی ایپلیکیشن کو فعال رکھ سکتے ہیں—یہاں تک کہ انحطاطی حالت میں بھی۔

اس گائیڈ میں، ہم فال بیک پیٹرن، اسے لاگو کرنے کے لیے عام حکمت عملی، یہ دوسرے لچکدار نمونوں کے ساتھ کس طرح تعامل کرتا ہے، اور جاوا (Resilience4j) اور Go میں فال بیک منطق کیسے لکھیں گے اس کا جائزہ لیں گے۔


حقیقی دنیا کی تشبیہ: کافی شاپ بیک اپ پلان

تصور کریں کہ آپ لیٹ خریدنے کے لیے مقامی کافی شاپ میں جاتے ہیں۔ بارسٹا آپ کا آرڈر داخل کرتا ہے، لیکن جب آپ اپنے کارڈ کو ٹیپ کرنے جاتے ہیں، تو ادائیگی کا ٹرمینل کنکشن کی خرابی کو چمکاتا ہے — دکان کے انٹرنیٹ فراہم کنندہ کو بندش کا سامنا ہے۔

کیا کافی شاپ فوری طور پر لائٹس بند کر دیتی ہے، دروازے بند کر دیتی ہے، اور تمام گاہکوں کو گھر بھیج دیتی ہے؟

ہرگز نہیں۔ وہ ایک فال بیک حکمت عملی نافذ کرتے ہیں:

  • اگر ان کے پاس نقد رقم ہے، تو وہ پوچھتے ہیں کہ کیا آپ نقد رقم سے ادائیگی کر سکتے ہیں۔
  • اگر آپ ایک باقاعدہ گاہک ہیں، تو بیرسٹا آپ کا نام لکھ سکتا ہے اور ایک لیجر میں آرڈر دے سکتا ہے اور آپ سے اگلی ملاقات پر ادائیگی کے لیے کہہ سکتا ہے۔
  • وہ ایک آف لائن کارڈ ریڈر استعمال کر سکتے ہیں جو کارڈ ٹوکن کو مقامی طور پر اسٹور کرتا ہے اور انٹرنیٹ کے ٹھیک ہونے پر بعد میں ادائیگی پر کارروائی کرتا ہے۔
فال بیک پیٹرن آرکیٹیکچر ڈایاگرام بنیادی سروس کی ناکامی اور کیشڈ/بیک اپ ڈیٹا کو بازیافت کرنے کے لیے فال بیک ہینڈلر کو روٹنگ دکھا رہا ہے

سافٹ ویئر ڈیزائن میں: کافی آرڈر کلائنٹ کی درخواست ہے۔

  • کارڈ ٹرمینل بنیادی ڈاؤن اسٹریم سروس ہے (مثال کے طور پر، ایک ادائیگی گیٹ وے API)۔
  • انٹرنیٹ کی بندش ایک نیٹ ورک ٹائم آؤٹ یا سروس کریش ہے۔ دی لیجر/آف لائن ریڈر فال بیک ایگزیکیوشن پاتھ ہے۔

عام فال بیک حکمت عملی

کاروباری منطق اور ناکام سروس کی تنقید پر منحصر ہے، آپ متعدد فال بیک حکمت عملیوں میں سے انتخاب کر سکتے ہیں:

1. جامد ڈیفالٹ ویلیوز

سب سے آسان حکمت عملی ایک محفوظ، پہلے سے تشکیل شدہ جامد قدر کو واپس کرنا ہے۔ یہ غیر اہم خصوصیات کے لیے انتہائی مؤثر ہے جہاں خالی یا ڈیفالٹ ڈیٹا ڈسپلے کرنا قابل قبول ہے۔

  • مثال: اگر پروفائل پرسنلائزیشن سروس ناکام ہوجاتی ہے، تو ڈیفالٹ اوتار کی تصویر اور عمومی سلام واپس کریں۔
  • مثال: اگر کوئی سفارشی سروس ناکام ہوجاتی ہے تو غلطی کرنے کی بجائے ایک خالی فہرست یا یونیورسل بیسٹ سیلرز کی ہارڈ کوڈ شدہ فہرست واپس کریں۔

2. کیش شدہ جوابات (Stale-While-Revalidate)

اگر لائیو ڈیٹا دستیاب نہیں ہے، تو آپ صرف پڑھنے کے لیے واپس آسکتے ہیں، مقامی کیشے کے باسی ڈیٹا یا Redis جیسے تیزی سے تقسیم شدہ میموری اسٹور۔

  • مثال: اگر کوئی پروڈکٹ انوینٹری سروس بند ہوجاتی ہے، تو 5 منٹ پہلے سے کیش شدہ اسٹاک میں مقدار کو ظاہر کریں، اس کے ساتھ ایک لطیف UI پیغام بھی ظاہر کرتا ہے کہ ہوسکتا ہے کہ ڈیٹا مکمل طور پر اپ ٹو ڈیٹ نہ ہو۔
  • مثال: اگر صارف کی ترتیبات کی سروس ناکام ہوجاتی ہے، تو ان کے لاگ ان کے بہاؤ کو روکنے کے بجائے کیش شدہ صارف پروفائل لوڈ کریں۔

3. متبادل سروس (ملٹی پرووائیڈر)

ایک اہم آپریشن کو انجام دیتے وقت جس کا کامیاب ہونا ضروری ہے، آپ ایک ثانوی سروس فراہم کنندہ کو بیک اپ کے طور پر تشکیل دے سکتے ہیں۔

  • مثال: اگر آپ کا بنیادی ادائیگی کا گیٹ وے (مثلاً، اسٹرائپ) 5xx کی غلطی یا وقت ختم ہو جاتا ہے، تو فال بیک میکانزم فوری طور پر لین دین کی درخواست کو ثانوی گیٹ وے (مثلاً، PayPal یا Adyen) پر بھیج دیتا ہے۔
  • مثال: اگر ایک جیو کوڈنگ API ناکام ہوجاتا ہے، تو ثانوی میپنگ فراہم کنندہ کے پاس واپس جائیں۔

4. بعد کے لیے قطار (اسینکرونس بفر)

تحریری کارروائیوں کے لیے جن کے لیے فوری مطابقت پذیر پروسیسنگ کی ضرورت نہیں ہے، فال بیک مقامی قطار یا ڈیٹا بیس میں درخواست کو بعد میں دوبارہ آزمانے کے لیے بفر کر سکتا ہے۔

  • مثال: اگر کوئی ای میل نوٹیفکیشن سروس بند ہے، تو نوٹیفکیشن پے لوڈ کو ڈیڈ لیٹر قطار یا مقامی ڈیٹا بیس ٹیبل پر لکھیں۔ ایک بیک گراؤنڈ ورکر اس قطار سے پڑھے گا اور نوٹیفکیشن سروس کے دوبارہ صحت مند ہونے کے بعد ای میلز ڈیلیور کرے گا۔

The Resilence Trio: دوبارہ کوشش کریں بمقابلہ سرکٹ بریکر بمقابلہ فال بیک

ایک انتہائی لچکدار فن تعمیر کے لیے، آپ کو فال بیک پیٹرن کو دوبارہ کوشش اور سرکٹ بریکر پیٹرن کے ساتھ جوڑنے کی ضرورت ہے۔ وہ دفاع کی تین سطحی لائن بناتے ہیں:

پیٹرن کردار ایکشن منظر نامہ
پیٹرن کی دوبارہ کوشش کریں قلیل مدتی عارضی خرابیوں کو حل کرتا ہے۔ تھوڑی تاخیر کے بعد درخواست کو دہرایا جاتا ہے (بیک آف + جٹر)۔ مختصر نیٹ ورک پیکٹ ڈراپ، ساکٹ ری سیٹ۔
سرکٹ بریکر وسائل کی تھکن کو روکتا ہے۔ فیل ہونے والی سروس کی کالوں کو فوری طور پر بلاک کرنے کے لیے ٹرپس کھلے ہیں (ناکام تیز)۔ مستقل سروس ڈاؤن ٹائم، ڈیٹا بیس میں تعطل۔
فال بیک پیٹرن صارف کے تجربے کو محفوظ رکھتا ہے۔ پرائمری کال ناکام ہونے یا بلاک ہونے پر ایک متبادل کارروائی کو انجام دیتا ہے۔ جب دوبارہ کوششیں ختم ہو جائیں یا سرکٹ بریکر کھلا ہو۔

وہ ایک ساتھ کیسے کام کرتے ہیں۔

  1. ایک آنے والی درخواست سروس گیٹ وے سے ٹکراتی ہے۔
  2. درخواست سرکٹ بریکر سے گزرتی ہے۔
  3. اگر سرکٹ بریکر بند ہے تو درخواست دوبارہ کوشش ریپر کے پاس جاتی ہے، جو اصل کال کرتا ہے۔
  4. اگر کوئی عارضی غلطی ہوتی ہے، تو دوبارہ کوشش کرنے کا طریقہ کار دوبارہ کال کرنے کی کوشش کرتا ہے۔
  5. اگر تمام کوششیں ناکام ہو جاتی ہیں، یا اگر سرکٹ بریکر پہلے سے ہی کھلا ہوا تھا (وسائل بچانے میں تیزی سے ناکام ہو رہا ہے)، فال بیک ہینڈلر ناکامی کو روکتا ہے اور انحطاط شدہ/کیش شدہ جواب واپس کرتا ہے۔

کوڈ پر عمل درآمد

آئیے دیکھتے ہیں کہ ہم جاوا اور گو دونوں میں فال بیک منطق کو کیسے نافذ کر سکتے ہیں۔

1. Java (Resilience4j)

جاوا میں، Resilience4j غلطی رواداری کے لیے انڈسٹری کا معیار ہے۔ ہم تشریحات یا پروگرام کے ذریعے اعلانیہ طور پر فال بیک طریقہ کی وضاحت کر سکتے ہیں۔

import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;

@Service
public class ProductService {

    private final InventoryClient inventoryClient;
    private final CacheManager cacheManager;

    public ProductService(InventoryClient inventoryClient, CacheManager cacheManager) {
        this.inventoryClient = inventoryClient;
        this.cacheManager = cacheManager;
    }

    // Bind this method to a circuit breaker. If it fails or is open, route to fallback
    @CircuitBreaker(name = "inventoryService", fallbackMethod = "getInventoryFallback")
    public List<String> getProductInventory(String category) {
        return inventoryClient.fetchStockByCategory(category);
    }

    // Fallback method must have the same return type and accept the same parameters,
    // plus a Throwable parameter containing the error that triggered it
    public List<String> getInventoryFallback(String category, Throwable throwable) {
        System.err.println("Primary inventory service failed: " + throwable.getMessage());
        
        // Attempt to fetch from local cache (Strategy 2)
        List<String> cachedStock = cacheManager.get("inventory:" + category, List.class);
        if (cachedStock != null) {
            return cachedStock;
        }

        // Return static empty list if cache is empty (Strategy 1)
        return Collections.emptyList();
    }
}

2. جاؤ (گولانگ)

گو میں، ہم فنکشنل پروگرامنگ پیٹرن کا استعمال کرتے ہوئے صاف فال بیک ڈیکوریٹر لکھ سکتے ہیں، جو ہمیں کسی بھی ایگزیکیوشن ہینڈلر کو سیکنڈری ہینڈلر کے ساتھ لپیٹنے کی اجازت دیتا ہے۔

package main

import (
	"context"
	"errors"
	"fmt"
	"time"
)

// Request represents a simple payload
type Request struct {
	UserID string
}

// Response represents the returned data
type Response struct {
	Data   string
	Status string
}

// ServiceFunc represents our primary function signature
type ServiceFunc func(ctx context.Context, req Request) (Response, error)

// WithFallback wraps a service function with fallback logic
func WithFallback(primary ServiceFunc, fallback ServiceFunc) ServiceFunc {
	return func(ctx context.Context, req Request) (Response, error) {
		res, err := primary(ctx, req)
		if err != nil {
			fmt.Printf("[Warning] Primary call failed: %v. Running fallback...\n", err)
			return fallback(ctx, req)
		}
		return res, nil
	}
}

func main() {
	// 1. Define primary service that occasionally fails
	primaryService := func(ctx context.Context, req Request) (Response, error) {
		return Response{}, errors.New("database connection timeout (504)")
	}

	// 2. Define fallback service that retrieves cached data
	fallbackService := func(ctx context.Context, req Request) (Response, error) {
		// Simulating cached read
		return Response{
			Data:   fmt.Sprintf("Stale cached profile data for user %s", req.UserID),
			Status: "DEGRADED (CACHED)",
		}, nil
	}

	// 3. Wrap them together
	resilientService := WithFallback(primaryService, fallbackService)

	// 4. Execute
	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancel()

	req := Request{UserID: "user_992"}
	response, err := resilientService(ctx, req)
	if err != nil {
		fmt.Printf("Operation completely failed: %v\n", err)
	} else {
		fmt.Printf("Response Received:\n - Status: %s\n - Data: %s\n", response.Status, response.Data)
	}
}

فال بیک پیٹرن کے لیے بہترین طریقے

  1. فال بیک پاتھ کو انحصار سے پاک رکھیں: فال بیک منطق کو انہی ڈاون اسٹریم سسٹمز یا انفراسٹرکچر پر انحصار نہیں کرنا چاہیے جو ابھی ناکام ہوا ہے۔ اگر آپ کا ڈیٹا بیس ڈاؤن ہے تو، اسی سرور پر کسی دوسرے ڈیٹا بیس کے استفسار پر واپس آنے کا امکان بھی ناکام ہو جائے گا۔
  2. Execute Fast: فال بیک لاجک کو تیزی سے کام کرنا چاہیے۔ اپنے فال بیک راستوں میں پیچیدہ کمپیوٹیشنز یا سست نیسٹڈ کالز سے پرہیز کریں۔ مقصد یہ ہے کہ صارف کو جلد از جلد جواب واپس کیا جائے۔
  3. الرٹ اور مانیٹر: ہمیشہ فال بیک ایگزیکیوشن اور انکریمنٹ ٹیلی میٹری کاؤنٹرز کو لاگ ان کریں۔ اگر آپ کا سسٹم فال بیک پاتھ پر عمل کر رہا ہے، تو اس کا مطلب ہے کہ سسٹم تنزلی کی حالت میں کام کر رہا ہے۔ آپ کو یہ جاننے کے لیے الرٹس کی ضرورت ہوتی ہے کہ فال بیک کی شرح کب عام حد سے تجاوز کر جاتی ہے۔
  4. UI کو لچکدار بنائیں: یہ یقینی بنانے کے لیے فرنٹ اینڈ انجینئرز کے ساتھ مل کر کام کریں کہ UI کو کلائنٹ سائیڈ لے آؤٹ کو توڑے بغیر فال بیک پے لوڈز (جیسے خالی مجموعے یا جزوی حالتوں) کو قبول کرنے کے لیے ڈیزائن کیا گیا ہے۔

نتیجہ

فال بیک پیٹرن مائیکرو سروس کی قابل اعتمادی کے لیے حتمی انشورنس پالیسی ہے۔ ناکامیوں کا اندازہ لگا کر اور خوبصورت، فال بیک منطق فراہم کر کے، آپ سخت کریشوں کو ٹھیک ٹھیک، قابل انتظام رکاوٹوں میں بدل دیتے ہیں۔ اس پیٹرن کو دوبارہ کوششوں اور سرکٹ بریکر کے ساتھ ملانا یقینی بناتا ہے کہ آپ کی ایپلیکیشن صارفین کی خدمت جاری رکھتے ہوئے بڑی بیرونی بندشوں کو برداشت کر سکتی ہے۔