CodeGym /Kurslar /ChatGPT Apps /Sistemin dayanıqlılığı: timeouts, circuit breakers, bulkh...

Sistemin dayanıqlılığı: timeouts, circuit breakers, bulkheads, vebhuk fırtınalarına qarşı müdafiə

ChatGPT Apps
Səviyyə , Dərs
Mövcuddur

1. Niyə ümumiyyətlə ChatGPT App-də “dayanıqlılıq” barədə düşünmək lazımdır

Adi veb-tətbiqdə istifadəçi heç olmasa URL-i, brauzerin spinerini görür, səhifəni yeniləyə bilir. ChatGPT-də istifadəçi bir ekran görür: çat və sizin App. Nəsə ləngiyəndə o, günahkarın kim olduğunu ayırd etmir — OpenAI, sizin Gateway, ödəniş sistemi, yoxsa qonşu analitika mikroxidməti. Onun üçün bunların hamısı “ChatGPT + sizin App”dir.

Əgər tool-call 3060 saniyə asılı qalırsa, model gözləyir, gözləyir… və ən yaxşı halda gecikməyə görə üzr istəyir. Ən pis halda — sizin backend-dən məlumatlar əvəzinə cavabı uydurur. Odur ki, dayanıqlılıq təkcə SRE və uptime haqqında deyil, həm də cavabın keyfiyyəti, modelin davranış tonu və Store-dakı metrikalar haqqındadır.

ChatGPT App ekosistemində bir neçə müstəqil kontur var:

  • ChatGPT ↔ MCP Gateway.
  • Gateway ↔ sizin backend-/REST-servisləriniz (Gift REST API, Commerce REST API, Analytics Service və s.).
  • Sizin servislər ↔ xarici API-lər (LLM, ödənişlər, kataloqlar).
  • Daxil olan vebhuklar (ACP, Stripe, istənilən inteqrasiyalar) ↔ sizin işləyicilər.

Məsələ ondadır ki, bir yerdə nasazlıq zəncirə səbəb ola bilər: Gateway vicdanla ilişmiş servisi gözləyir, worker-lər dolur, bağlantılar tükənir, müştərilər retry edir və bir neçə dəqiqədən sonra klassik “sistema BEL’” baş verir: hər şey eyni anda yanır və batır. Məhz bundan bu gün danışdığımız dörd pattern qoruyur:

  • Timeouts — biz heç vaxt sonsuz gözləmirik.
  • Circuit breaker — biz bağlı qapını döymürük.
  • Bulkheads — “otsek”lər qururuq ki, bütün gəmi batmasın.
  • Vebhuk fırtınalarına qarşı müdafiə — vebhukların dublikatlarla, sıçrayışlarla və retry-lərlə gəldiyini qəbul edirik və buna hazırlaşırıq.

2. Timeouts: biz sonsuz gözləmirik

Timeout nədir və onsuz niyə hər şey pis olur

Timeout — asılılıqdan (baza, MCP-server, xarici HTTP API, model) cavabı gözləməyə hazır olduğunuz maksimal vaxtdır. Cavab verilən müddət ərzində gəlmirsə — çağırışı uğursuz sayırıq, resursları azad edirik və anlaşılan səhv və ya fallback qaytarırıq.

Timeout olmadan sorğular:

  • sonsuz gözləmədə qala bilər,
  • bağlantıları və thread pool-u məşğul edə bilər,
  • sonrakı sorğuları bloklaya bilər,
  • kaskadlı nasazlıqlara səbəb ola bilər.

Sadə pattern: “35 saniyədən sonra proqnozlaşdırılan rədd, 5 dəqiqə anlaşılmaz sükutdan daha yaxşıdır”.

Unutmayın, bir neçə səviyyədə timeout-lar var:

  • proksi/ballanser səviyyəsində (Cloudflare, Nginx),
  • MCP Gateway səviyyəsində (mikroservislərə HTTP-klientlər),
  • servislərin özündə (BD, xarici API-lər, LLM çağırışları).

Ümumilikdə ChatGPT üçün adi əməliyyatlarda tool-call-un ümumi vaxtını 510 saniyə aralığında saxlamaq, xüsusilə ağırları isə maksimum 2030 saniyəyə qədər tutmaq məntiqlidir. Daha uzunu — demək olar ki, zəmanətli pis UX deməkdir.

TypeScript-də sadə fetchWithTimeout

Gəlin praktikadan başlayaq. GiftGenius MCP Gateway-də gift-seçici, commerce-servis, analitika ilə danışan köməkçi HTTP-klient var. Standart fetch-i timeout-lu funksiya ilə bürüyək:

// src/gateway/httpClient.ts
export async function fetchWithTimeout(
  url: string,
  opts: RequestInit & { timeoutMs?: number } = {}
) {
  const { timeoutMs = 5000, ...rest } = opts;
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), timeoutMs);

  try {
    return await fetch(url, { ...rest, signal: controller.signal });
  } finally {
    clearTimeout(timeoutId);
  }
}

İndi Gateway kodunda heç vaxt “çılpaq” fetch etmirik, yalnız bu helper-dən istifadə edirik:

// src/gateway/giftClient.ts
import { fetchWithTimeout } from "./httpClient";

export async function callGiftService(path: string) {
  const res = await fetchWithTimeout(
    process.env.GIFT_SERVICE_URL + path,
    { timeoutMs: 4000 }
  );

  if (!res.ok) {
    throw new Error(`gift_service_${res.status}`);
  }
  return res.json();
}

Bu yanaşma zəmanət verir ki, hətta gift-servis ilişsə belə, 4 saniyədən sonra bağlantını kəsəcəyik və ChatGPT-yə MCP-səhv qaytara biləcəyik, əlaqəni sonadək saxlamayacağıq.

GiftGenius-da timeout-ları harada qoymaq lazımdır

Bizim GiftGenius nümunəsində:

  • Gateway səviyyəsində: Gift REST API, Commerce REST API, Analytics Service / REST API çağırışlarına timeout-lar.
  • Bu servislərin içində: BD-yə, ACP/ödənişlərə, xarici tövsiyə API-lərinə çağırışlara timeout-lar.
  • Gateway girişində: ChatGPT-dən gələn sorğuya ümumi timeout ki, tool-call “sonsuz spiner”ə çevrilməsin.

Vacibdir ki, yuxarı səviyyədə gözləmə vaxtı daxili səviyyələrdən bir az böyük olsun. Məsələn, Gateway backend-i 5 saniyə gözləyirsə, backend BD-ni 3 saniyə gözləyirsə, emal və nəticənin seriyalaşdırılması üçün ehtiyatımız var.

Taymautları ChatGPT modelinə necə izah etməli

ChatGPT üçün semantik səhvlər qaytarmaq vacibdir, əlaqəni susqunluqla kəsmək yox. Abstrakt 500 əvəzinə modelin istifadəçiyə səsləndirə biləcəyi strukturlu MCP-səhv qaytarmaq daha yaxşıdır: “Hədiyyə seçimi xidməti hazırda yüklənib, bir azdan yenidən cəhd et” və s.

Bu o deməkdir ki, Gateway-də taymaut olduqda:

  1. AbortError-u və ya bizim timeout_…-u tutmaq lazımdır.
  2. Məzmunlu kod və qısa təsvirlə MCP-cavab formalaşdırın.
  3. Modelə bunun insanı necə izah etməyi seçmək imkanı verin.

Taymautlar ilişmiş sorğu problemini həll edir, amma asılılıq kütləvi şəkildə düşməyə başlayanda, onlar eyni uğursuz cəhdlərin qarını dayandırmır. Burada növbəti müdafiə səviyyəsinə — circuit breaker-ə ehtiyac var.

3. Circuit breaker: “avtomat” ölən servislərə qarşı

İntuisiya: niyə təkcə bir taymaut kifayət etmir

Artıq taymautlarla ayrı-ayrı çağırışların gözləmə müddətini məhdudlaşdırmağı öyrəndik. Taymaut bir konkret çağırışı qoruyur. Amma asılılıq “bərk” öləndə (məsələn, commerce-servis hər sorğuda OOM (Out Of Memory) ilə yıxılır), yenə də ona gedəcəyik, hər dəfə 35 saniyə gözləyəcəyik, səhv tutacağıq, şəbəkəni və CPU-nu yükləyəcəyik və yenə gözləyəcəyik.

Circuit breaker (avtomat) yaddaş əlavə edir: səhvləri və taymautları izləyir və onlar çox olanda, bu servizə ümumiyyətlə sorğu göndərməyi dayandırır. Bunun əvəzinə dərhal sürətli rədd və ya fallback qaytarır. Bir müddətdən sonra ehtiyatla half-open rejimində yenidən yoxlayır.

Avtomatın klassik vəziyyətləri:

  • Closed — hər şey normaldır, sorğular gedir.
  • Open — servis “ölü” sayılır, sorğular getmir, dərhal səhv.
  • Half-open — məhdud sayda sorğunu sınayırıq; uğurludursa — closed-a qayıdırıq, yenə düşərsə — yenidən open.

Sadə circuit breaker sxemi

Kiçik diaqram:

stateDiagram-v2
    [*] --> Closed
    Closed --> Open: çox sayda səhv
    Open --> HalfOpen: cooldown bitdi
    HalfOpen --> Closed: ardıcıl bir neçə uğur
    HalfOpen --> Open: yenə səhvlər
    Open --> Open: sürətli rədd

TypeScript-də mini circuit breaker reallaşdırması

Prodda adətən hazır kitabxanalardan istifadə olunur (Node.js üçün məsələn, opossum və ya yüngül self-made həllər var), amma mexanikası anlaşılsın deyə kompakt bir klass kifayətdir.

Commerce-modulu çağırışı ətrafında çox sadələşdirilmiş breaker nümunəsi:

// src/gateway/circuitBreaker.ts
type State = "closed" | "open" | "half-open";

export class CircuitBreaker {
    private state: State = "closed";
    private failureCount = 0;
    private nextAttemptAt = 0;

    constructor(
        private readonly failureThreshold = 5,
        private readonly cooldownMs = 30_000
    ) {}

    async call<T>(fn: () => Promise<T>): Promise<T> {
        const now = Date.now();

        if (this.state === "open") {
            if (now < this.nextAttemptAt) {
                throw new Error("circuit_open");
            }
            this.state = "half-open";
        }

        try {
            const result = await fn();
            this.onSuccess();
            return result;
        } catch (err) {
            this.onFailure();
            throw err;
        }
    }

    private onSuccess() {
        this.failureCount = 0;
        this.state = "closed";
    }

    private onFailure() {
        this.failureCount++;
        if (this.failureCount >= this.failureThreshold) {
            this.state = "open";
            this.nextAttemptAt = Date.now() + this.cooldownMs;
        }
    }
}

Və commerce-servis müştərisində istifadə:

// src/gateway/commerceClient.ts
const commerceBreaker = new CircuitBreaker(3, 20_000);

export async function callCommerce(path: string) {
    return commerceBreaker.call(async () => {
        const res = await fetchWithTimeout(
            process.env.COMMERCE_URL + path,
            { timeoutMs: 3000 }
        );
        if (!res.ok) throw new Error(`commerce_${res.status}`);
        return res.json();
    });
}

Burada, commerce kütləvi şəkildə səhvlərlə cavab verməyə və ya taymauta qədər çatmamağa başlayanda, bir neçə uğursuzluqdan sonra breaker open vəziyyətinə keçir. Bu vəziyyətdə cooldownMs ərzində servizə ümumiyyətlə getmirik və dərhal circuit_open səhvi qaytarırıq.

Breaker “kəsəndə” ChatGPT baxımından nə görmək daha yaxşıdır

ChatGPT baxımından daha yaxşısı odur ki, siz:

  • Tez MCP-səhvi “commerce_unavailable” və ya “gift_service_overloaded” qaytarasınız.
  • Anlaşılan təsvir əlavə edəsiniz: “Ödəniş xidməti müvəqqəti əlçatan deyil, gəlin bir azdan cəhd edək”.
  • Səhvi sonsuz retry-larla gizlətməyəsiniz.

Bu elə haldır ki, “sürətli, dürüst rədd” uzun asılmadan daha yaxşıdır. Xüsusən checkout-da: istifadəçi dürüst mesaja daha asan dözər, nəinki 40 saniyə spinerə baxıb “nəsə qaydasında deyil” alar.

Taymautlar və breaker “pis” və ya yatan asılılıqlardan qoruyur, amma bir yük növü bütün resursları yeyib sistemin qalan hissəsini boğanda problemi həll etmir. Bunun üçün daha bir qat — bulkheads lazımdır.

4. Bulkheads: “otsek” izoləsiyası ki, biri bütün gəmini batırmasın

Gəmi analoqu

Bulkhead pattern-i gəmidəki arakəsmələrin şərəfinə adlandırılıb: bir otsəkdə deşik olsa, su bütün gəmiyə yayılmır. Arxitekturada bu belədir: fərqli iş istiqamətləri arasında resursları bölmək ki, bir yüklənmiş servis hər şeyi — CPU, bağlantılar, pullar — yeyib kritik yolları yıxmasın.

Mikroservislərdə bu adətən ayrıca aşağıdakılarla edilir:

  • HTTP-bağlantı pulları,
  • thread/worker pulları,
  • növbələr/topiklər,
  • hətta kritik əməliyyatlar üçün ayrıca BD klasterləri.

Fikir budur ki, hədiyyə tövsiyə servisi ləng işləməyə və ilişməyə başlasa, yalnız öz resurslarını tükəndirər, amma checkout və avtorizasiyanı yıxmaz.

Node.js və MCP Gateway dünyasında bulkheads

Node.js-də klassik mənada thread-lər yoxdur (event loop və worker-lər var), amma hər istiqamət üçün paralel tapşırıqların sayını məhdudlaşdıra bilərik.

Nümunə: Gateway-də üç xarici asılılıq var:

  • Gift-servis (hədiyyə seçimi, ağır LLM çağırışları).
  • Commerce-servis (checkout, ACP).
  • Analytics-servis (hadisələrin loglanması).

Hər biri üçün eyni vaxtda sorğulara sadə limitlər qoya bilərik.

Məsələn, paralelliyi məhdudlaşdırmaq üçün kiçik “semafor”:

// src/gateway/bulkhead.ts
export class Bulkhead {
    private active = 0;
    private queue: (() => void)[] = [];

    constructor(private readonly maxConcurrent: number) {}

    async run<T>(fn: () => Promise<T>): Promise<T> {
        if (this.active >= this.maxConcurrent) {
            await new Promise<void>((resolve) => this.queue.push(resolve));
        }
        this.active++;

        try {
            return await fn();
        } finally {
            this.active--;
            const next = this.queue.shift();
            if (next) next();
        }
    }
}

Və servislər üçün istifadə:

// src/gateway/clients.ts
import { Bulkhead } from "./bulkhead";

const giftBulkhead = new Bulkhead(10);      // eyni vaxtda ən çox 10
const commerceBulkhead = new Bulkhead(3);   // checkout ciddi məhdudlaşdırılıb
const analyticsBulkhead = new Bulkhead(50); // çox ola bilər

export async function callGiftWithBulkhead(fn: () => Promise<any>) {
    return giftBulkhead.run(fn);
}

export async function callCommerceWithBulkhead(fn: () => Promise<any>) {
    return commerceBulkhead.run(fn);
}

Beləliklə, GPT kütləvi şəkildə “mənə 30 çətin hədiyyə seçimi et” desə belə, onlar maksimum 10 paralel yerinə yetiriləcək, checkout isə öz ayrıca limitindən istifadə edərək işləməyə davam edəcək.

GiftGenius: hansı bölmələri istəyirik

GiftGenius-də məntiqli ayrı bölmələr:

  • Hədiyyə seçimi (LLM-ağır, daha az kritik, yavaşlada bilərik).
  • Checkout/ACP (super-kritik, maksimum qorumaq lazımdır).
  • Analitika/loglar (vacibdir, amma bir az gecikməyə dözə bilər).

Daha inkişaf etmiş arxitekturada onları ayrıca resurslarla müxtəlif klasterlər kimi dəploy edirsiniz, amma bu mühazirə çərçivəsində əsas fikir vacibdir: ikinci dərəcəli funksiyalara “bütün oksigeni yeməyə” icazə verməyin.

Bu üç pattern — taymautlar, circuit breaker və bulkheads — sizin çölə, asılılıqlarınıza necə getdiyinizlə bağlıdır. Amma dayanıqlılığa başqa bir təhdid sinfi də var: ideal çıxan çağırışlar olsa belə sizi çökdürə bilən daxil olan hadisə axınları. Tipik nümunə — vebhuk fırtınaları.

5. Vebhuk fırtınaları: dünya sizə hadisələri siz hazır olandan tez-tez göndərəndə

Vebhuklar reallıqda necə davranır

Dayanıqlılıq problemlərinin dördüncü mənbəyi — daxil olan hadisələr: ACP, Stripe və digər sistemlərdən vebhuklar. Elə bunlar, taymautlar, circuit breaker-lər və bulkhead-lər artıq quraşdırılmış olsa belə, həqiqi “fırtına” yarada bilər.

Vebhuklar “sorğu üzrə” HTTP-sorğusu deyil, xarici sistemlərin (Stripe, ACP, xarici mağazalar və s.) “push”-hadisələridir. Bir neçə xoşagəlməz xüsusiyyətləri var:

  • Çatdırılma ən azı bir dəfə (at-least-once) — deməli, dublikatlar qaçılmazdır.
  • Çatdırılma ardıcıllığı zəmanətli deyil.
  • Səhvlərdə sevirlər retry etməyi: əvvəl saniyədən sonra, sonra 10, sonra dəqiqədən sonra… siz 2xx qaytarmayana qədər.
  • Pikdə (məsələn, endirimdə) onlar paketlərlə gəlir və “fırtına” yaradır.

Əgər işləyiciniz idempotent deyilsə və çox uzun işləyirsə, boğaz olur, bütün növbə dolur, retry-lər isə fırtınanı gücləndirir. Nəticədə bazanı, növbəni, worker-pulları və zəncirvari olaraq sistemi yıxa bilərsiniz.

Fırtınalardan qorunmanın əsas prinsipləri

Şansı ciddi artıran bir neçə fikir var:

Birincisi, queue-first, process-later. İdealda daxil olan vebhuk sinxron olaraq ağır işi yerinə yetirməməlidir. Onun əvəzinə imzanı/formatı mümkün qədər tez yoxlayır, tapşırığı növbəyə qoyur və 200 OK cavab verir. Emal fon worker-də asinxron gedir. ChatGPT üçün “sürətli təsdiq” lazımdırsa, ayrıca bildiriş konturu saxlaya bilərsiniz.

İkincisi, işləyicinin idempotentliyi. Eyni əməliyyat üzrə təkrarlanan vebhuk “sifarişi bir də etməməli” və ya “pulu iki dəfə tutmamalıdır”. Adətən bu, idempotency key və ya eventId saxlanması və hadisəni artıq emal edib-etmədiyimizin yoxlanması ilə həll olunur.

Üçüncüsü, qəbul edən tərəfdə rate limiting və circuit breaker. Göndərən fırtına etsə belə, siz:

  • IP/abunə/endpoint üzrə RPS-i məhdudlaşdıra,
  • müvəqqəti 429 və ya 503 qaytararaq retry-ləri ləngidə,
  • sındırılmış downstream-ə axını tökməmək üçün breaker istifadə edə bilərsiniz (məsələn, sifarişlər bazası).

GiftGenius-də Next.js vebhuk işləyicisi nümunəsi

Tutaq ki, ACP/ödəniş sistemi sifariş statusu barədə vebhuk göndərir POST /api/commerce/webhook ünvanına. Biz istəyirik:

  • hadisəni tez qəbul edib növbəyə qoymaq,
  • onu sinxron emal etməmək,
  • dublikatlardan sınmamaq.

Sadələşdirilmiş nümunə (imza yoxlaması və real növbəsiz — bu təhlükəsizlik və növbələr modullarında olacaq):

// app/api/commerce/webhook/route.ts
import { NextRequest, NextResponse } from "next/server";

// Burada Redis/queue ola bilərdi, hələlik massivlə imitasiya edirik
const inMemoryQueue: any[] = [];
const processedEvents = new Set<string>(); // idempotentlik (demo üçün)

export async function POST(req: NextRequest) {
    const event = await req.json();

    const eventId = event.id as string;
    if (processedEvents.has(eventId)) {
        return NextResponse.json({ ok: true, duplicate: true });
    }

    // Reallıqda burada imzanın və sxemin yoxlanması olacaq

    inMemoryQueue.push(event); // fon emal üçün növbəyə qoyuruq
    // Fon worker sonra emal edib ID-ni “emal olunub” kimi işarələyəcək
    return NextResponse.json({ ok: true });
}

Hələlik bu psevdoreallaşdırmadır, amma iki məqam vacibdir:

  1. Sinxron hissə maksimum yüngüldür.
  2. event.id ətrafında idempotentliyi nəzərdə tuturuq.

Real həyatda siz:

  • xarici növbədən (SQS, RabbitMQ, Kafka) istifadə edəcəksiniz,
  • emal olunmuş hadisələri BD-də saxlayacaqsınız,
  • vebhukun imzasını və payload versiyasını yoxlayacaqsınız,
  • bəlkə də işləyici ətrafında ayrıca Bulkhead/Breaker tətbiq edəcəksiniz.

Bu, GiftGenius kontekstində necə görünür

ACP/Stripe ilə vebhuklar üzərindən inteqrasiya olunmuş GiftGenius üçün fırtınalardan qorunma xüsusilə pik mövsümlərdə (Yeni il, Qara Cümə) vacibdir. Orada çoxlu hadisələr var:

  • intent-lərin yaradılması,
  • ödənişlərin təsdiqi,
  • ləğvlər,
  • geri qaytarmalar.

İşləyiciniz “uzanmağa” başlasa (məsələn, xarici API-lərə sorğulara görə), belə risklər var ki:

  • ACP retry etməyə başlayacaq,
  • hadisələr paketlərlə gələcək,
  • sifarişlər bazası və worker-pul dolacaq.

“Queue first” pattern-i + idempotentlik + girişdə rate limiting məhz belə ssenarilərdən sığortadır.

6. Bu pattern-lər birlikdə necə işləyir

İndi bütün bu pattern-ləri bir ssenaridə yığaq və “Hədiyyə seç və dərhal sifarişi rəsmiləşdir” real axınında necə işlədiklərinə baxaq.

“ChatGPT → Gateway → Gift Service → Commerce → vebhuklar” zəncirini ssenari nümunəsində nəzərdən keçirək:

İstifadəçi çatda deyir: “Hədiyyə seç və dərhal sifarişi rəsmiləşdir”.

  1. Model sizin suggest_and_checkout alətini çağırmağı qərar verir.
  2. Gateway gift-servisi fetchWithTimeout və gift-servisin bulkhead-i vasitəsilə çağırır.
  3. Əgər gift-servis ilişirsə — taymaut işə düşür; onun ətrafındakı breaker bir neçə səhvdən sonra open vəziyyətinə keçəcək və növbəti sorğular dərhal “gift_service_unavailable” MCP-səhvi alacaq.
  4. Əgər gift-servis cavab verirsə, Gateway commerce-servisi çağırır (yenə taymaut və ayrıca bulkhead ilə).
  5. Commerce ilə bağlı istənilən problemlər ayrıca circuit breaker-i işə salır, o, gift-dən daha sərt tənzimlənib (çünki checkout kritikdir).
  6. Uğurlu sifariş ACP-dən sizin /api/commerce/webhook-a vebhuka gətirib çıxarır; bu vebhuk hadisəni növbəyə qoyur və tez cavab verir; fon worker-lər ödənişi emal edir, eyni eventId üzrə təkrar vebhuklar isə dublikat kimi görməzlikdən gəlir.

Nəticədə:

  • İlişən hədiyyə seçimi servisi checkout-u yıxmır.
  • İlişən commerce bütün tool-calls-u dəqiqəlik spinerə çevirmir — ChatGPT tez bir məzmunlu səhv alır.
  • Vebhuk fırtınaları əsas HTTP konturunuzu sındırmır.
  • Deqradasiya yerlərini siz idarə edirsiniz: ödənişi yıxmaqdansa, müvəqqəti olaraq fərdiləşdirilmiş tövsiyələri söndürmək daha yaxşıdır.

7. Sizin App üçün kiçik praktiki yoxlama siyahısı (narrativ formada)

Ümumiləşdirsək, MCP/Gateway-li tipik ChatGPT App-də aşağıdakı suallar üzrə ardıcıllıqla getmək məntiqlidir.

Əvvəlcə bütün xarici çağırışlarda taymautların olub-olmadığını yoxlayırsınız. Bütün fetch kodu, BD və LLM sorğuları fetchWithTimeout kimi bir bükücüdən adekvat dəyərlərlə istifadə etməlidir. Sonsuz asıla biləcək yerlər olmaması vacibdir.

Sonra ən kövrək asılılıqları müəyyənləşdirirsiniz. Adətən bunlar ödənişlər, ACP, iri xarici API-lər və bəzən sizin sifarişlər bazanız olur. Onların ətrafında circuit breaker əlavə etmək, qətiyyən ölü servizə təkrarların lavinasından qorunmaq üçün məntiqlidir. Eyni zamanda breaker open vəziyyətində olanda ChatGPT-nin necə davranacağını əvvəlcədən qərar verirsiniz.

Bundan sonra resurslarınıza “bölmələr” kimi baxırsınız. Hər şey bir connection pool və bir worker-puldan keçir, yoxsa kritik əməliyyatlar (login, checkout) tövsiyə və analitika servisindən asılı olmayaraq öz paralellik limitlərinə malikdir? Əgər yoxdursa — ən azından paralel tapşırıqlara kobud limit kimi sadə bulkhead reallaşdırması əlavə edin.

Sonda bütün daxil olan vebhukların auditini aparırsınız. Onlarda idempotency key və ya eventId varmı, HTTP-işləyicidə ağır işi sinxron etməyə çalışırsınızmı və downstream müvəqqəti düşsə retry dalğasından sağ çıxmağı bacarırsınızmı. Əgər yox — məntiqi növbə və fon worker-lərə köçürün.

Belə addımlar ardıcıllığı super-mürəkkəb infrastruktur olmadan belə dayanıqlılığı xeyli artırır.

8. Timeouts, circuit breakers, bulkheads və vebhuk fırtınaları ilə işləyərkən tipik səhvlər

Səhv №1: “haradasa aşağıda” taymautların olmaması.
Tərtibatçılar tez-tez taymautu yalnız Gateway-də və ya yalnız frontend-də qoyur, backend-in içində isə BD, xarici API-lər və LLM-in də olduğunu unudurlar. Nəticədə, xarici sorğunun guya 5 saniyə taymautu var, amma içəridə BD-yə və ya ödəniş sisteminə bir çağırış dəqiqələrlə asılı qalır, connection pool-u bloklayır və kaskadlı nasazlıqlara səbəb olur.

Səhv №2: “birdən lazım olar” deyə nəhəng taymautlar.
Bəzən 60120 saniyə taymaut qoyurlar: “qoy çatdırsa, yaxşıdır”. ChatGPT kontekstində bu demək olar ki, həmişə pisdir. İstifadəçi çıxır, model uydurmağa başlayır, resurslarınız isə bu vaxt bloklanır. 510 saniyədən sonra anlaşılan təsvirlə dürüst rədd çox daha yaxşıdır.

Səhv №3: düşünülmüş UX-siz circuit breaker.
Bəzən breaker “quş qoymaq” üçün əlavə olunur, amma işə düşəndə istifadəçi və ya model anlaşılmayan 500, “ECONNREFUSED” və ya “axios error” alır. Nəticədə GPT vəziyyəti düzgün izah edə bilmir və uydurmağa başlayır. Həm insanlara, həm də modelə aydın olacaq səhv formulyarlarını öncədən düşünməyə dəyər.

Səhv №4: bulkhead yanaşması olmadan resursların qarışdırılması.
Klassik ssenari: bir tövsiyə (və ya analitika) servisi ləngiməyə başlayır, BD-yə bütün connection pool-u və ya thread-pool-u yeyir və ardınca checkout və login ölür. Bütün bunlar resurslar bölünmədiyinə görə. Ən azı hansısa bulkhead yanaşmasının olmaması elə vəziyyətə gətirir ki, ikinci dərəcəli funksiya bütün prod-u yıxa bilir.

Səhv №5: vebhukları adi sorğular kimi emal etmək.
Yeni başlayanlar vebhuk-işləyicisini adi controller kimi yazırlar: uzun biznes-məntiq, tərəfdaş API-lərə sorğular, idempotentlik yoxdur. Retry-lər və dublikatlar şəraitində bu, hadisələrin iki dəfə emalına, sifarişlərin qəribə vəziyyətlərinə və fırtınada yükdən yıxılmalara gətirib çıxarır.

Səhv №6: commerce ssenarilərində idempotentliyi görməzdən gəlmək.
Xüsusilə təhlükəlidir ki, ödəniş vebhuku sifarişi bir daha yaradıb və ya onun vəziyyətini təkrar dəyişə bilər. Idempotency key yoxlanışı və hadisənin emal statusunun saxlanması olmadan gec-tez ikiqat tutma və ya qəribə sifariş dublikatları alacaqsınız.

Səhv №7: hər şeyi setTimeout və “sehrli gecikmələrlə” düzəltməyə cəhd.
Bəzən race condition və fırtına problemlərini “100 ms gözləyək və hər şey yaxşı olacaq”la dolanmaq istəyirlər. Praktikada bu, davranışı daha da qeyri-sabit edir və real nasazlıqlardan qorumur. Düz yol — aydın taymautlar, circuit breaker, növbələr və idempotentlikdir, gecikmə “cadugərliyi” yox.

Səhv №8: kritik yolların prioritetləşdirilməməsi.
Checkout və login analitika və ya tövsiyə məntiqi ilə eyni limitlərdə yaşadıqda, istənilən overload həm kritik, həm də ikinci dərəcəli hissələri eyni dərəcədə yıxa bilər. Dayanıqlı dizaynda checkout və auth “toxunulmaz”dır: onlar üçün ayrıca resurslar, ayrıca limitlər, ayrıca aler və SLO var.

Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION