1. Axınlar niyə yükə xüsusilə həssasdır
Ötən hissələrdə GiftGenius üçün MCP‑hadisələrin, job.progress/job.completed statuslarının, async‑job‑ların və axın kanallarının (SSE/HTTP-stream) necə qurulduğunu artıq müzakirə etmişdik. İndi isə bu arxitektura real yük altında necə davranacaq — buna baxmaq vacibdir.
Sizdə hələlik bəzən hədiyyə seçimini işə salan bir istifadəçi olanda hər şey əladır. Amma GiftGenius production‑a çıxan kimi və eyni anda “bütün əməkdaşlara korporativ üçün hədiyyə seç” tipli yüzlərlə sorğu gələndə, birdən kəşf edirsiniz ki:
- serverdə yüzlərlə uzunömürlü SSE‑bağlantı var;
- worker‑lər hər xırda dəyişiklikdə job.progress göndərir;
- loglar günə qiqabaytlarla artır;
- istifadəçinin UI‑ı ləngiməyə başlayır, baxmayaraq ki, “server sanki yıxılmır”.
Klassik HTTP‑sorğu millisaniyə və ya saniyələrlə “yaşayır”. SSE və ya HTTP‑stream axını isə dəqiqələrlə, hətta saatlarla yaşaya bilər. O, bağlantını, yaddaşı, fayl deskriptorlarını tutur. Hər göndərilən event — JSON‑un seriyalaşdırılması, şəbəkə ilə kopiyalanma, GC işi deməkdir. Bunu “backend‑də sadəcə daha bir console.log” kimi görsəniz, sistem çox tez isidiciyə çevriləcək.
MCP‑hadisələrin daha bir xüsusiyyəti: onlar çox vaxt eyni tapşırıq üçün dəfələrlə generasiya olunur. Proqresi hər 0.1 % üçün yeniləyən worker, bir job üçün heyrətamiz sayda hadisə yaradır. Nəticədə “səs‑küy” əldə edirsiniz: çoxlu sayda xırda mesajlar ki, onlar:
- şəbəkə və CPU‑nu yükləyir;
- növbələri və bufferləri doldurur;
- debug və logların analizini ağrılı edir.
Bu səbəbdən həm axınlara, həm də MCP‑hadisələrə verilənlər bazasına sorğu və ya model çağırışı qədər ciddi yanaşmaq lazımdır: bunlar normallaşdırma, nəzarət və monitorinq tələb edən bahalı resurslardır.
Bunlarla baş etmək üçün yadda üç böyük mövzunu saxlayırıq:
- Rate‑limitlər — ümumiyyətlə neçə və hansı tezliklə hadisə/axın generasiya edib göndərə biləcəyimizi məhdudlaşdırırıq.
- Backpressure — istehlakçı istehsalçıya çatmadıqda buna reaksiyamız.
- Monitorinq və metriklər — nə baş verdiyini ölçürük və hər şey “qaynamağa” başlamazdan əvvəl görürük.
2. Axınların və hadisələrin rate‑limit edilməsi
Ən aydın olandan başlayaq — limitlərdən.
Başadüşülən odur ki, axın ssenarilərində “təhlükəli pozucu” rolunu çox vaxt müştəri yox, server oynayır. Adi REST‑API‑lərdə istifadəçini DDoS‑a çevirməmək üçün serverə sorğu sayını məhdudlaşdırırsınız. MCP və axınlar aləmində isə əks DDoS yaratmaq çox asandır: worker və ya MCP‑server müştərini saniyədə minlərlə hadisə ilə bombalayır.
Hansı limitlər lazımdır
Adətən üç istiqamətdə nəzərdən keçirilir.
Birincisi, istifadəçi və ya sessiya üzrə limitlər. Bir istifadəçiyə hərəsi öz SSE‑axını olan iyirmi paralel master‑vidcet açmağa icazə vermək olmaz. Məntiqli məhdudiyyət — sessiya üçün bir neçə aktiv axın və bir istifadəçi və ya icarəçi üçün running statusunda olan job sayına limit.
İkincisi, bir job üçün limitlər. Burada bizi hadisələrin tezliyi maraqlandırır. job.progress hadisələrini N millisaniyədən tez olmayaraq və ya yalnız nəzərəçarpan dəyişiklikdə, məsələn, hər 5 % artımda göndərmək kifayətdir. Kataloqdakı hər emal olunan məhsul üçün mesaj göndərməyə ehtiyac yoxdur. Payload ölçüsünü də məhdudlaşdırmaq mənalıdır: proqres hadisəsi özündə meqabaytlarla mətn daşımamalıdır.
Üçüncüsü, IP və ya təşkilat üzrə limitlər. Bu artıq sui‑istifadədən qorunmadır: kimsə tapşırıqları spam edən skript işə salırsa və ya tətbiqiniz qəfil populyar olursa. Burada artıq API‑gateway və proxy mexanizmləri işə düşür.
Hadisə tezliyi limitinin sadə reallaşdırılması
Gəlin GiftGenius worker‑ini nəzərdən keçirək: o, arxa planda uzun alıcı siyahısı üzrə hədiyyələr seçir və mütəmadi olaraq MCP‑bildiriş event/progress ilə proqresi göndərir. İstəyirik ki, hadisələr 500 millisaniyədən tez olmayaraq və faiz ən azı 5 bənd artdıqda göndərilsin.
Worker üçün şərti TS pseudo‑kod:
// tutaq ki, mcpClient.sendNotification(...) kimi bir şeyimiz var
let lastSentPercent = 0;
let lastSentAt = 0;
function reportProgress(jobId: string, percent: number, message: string) {
const now = Date.now();
const percentDelta = percent - lastSentPercent;
const timeDelta = now - lastSentAt;
// yalnız aşağıdakı hallarda göndəririk: ya >= 500 ms keçibsə, ya da artım >= 5 %
if (percentDelta >= 5 || timeDelta >= 500) {
mcpClient.sendNotification("event/progress", {
jobId,
percent,
message,
});
lastSentPercent = percent;
lastSentAt = now;
}
}
Bu yanaşma throttling adlanır: hadisələr axınını həm vaxta, həm də dəyər dəyişikliyinə görə “seyrəldirik”.
Əgər mərhələlərə bölmə edirsinizsə («Mərhələ 1/3», «Mərhələ 2/3»), məntiq daha da sadədir: hadisələri yalnız mərhələ dəyişəndə göndərin.
Eyni anda açıq axınların sayına limit
MCP‑server tərəfində böyük ehtimalla SSE üçün HTTP‑handler var:
// app/api/events/[userId]/route.ts (Next.js 16 App Router)
export async function GET(
req: Request,
{ params }: { params: { userId: string } },
) {
const userId = params.userId;
if (!canOpenMoreStreams(userId)) {
return new Response("Too many streams", { status: 429 });
}
const stream = new ReadableStream({
start(controller) {
registerSseClient(userId, controller);
},
cancel() {
unregisterSseClient(userId);
},
});
return new Response(stream, {
headers: { "Content-Type": "text/event-stream" },
});
}
canOpenMoreStreams funksiyası istifadəçi üçün hazırda açıq bağlantıların sayını yoxlayıb hədlə müqayisə edə bilər (məsələn, üç paralel axından çox olmasın). Limit aşılarsa, 429 qaytarırıq və GPT təlimatlarında modelə izah edirik ki, belə halda daha bir uzun “master” işə salmaq əvəzinə istifadəçiyə «artıq aktiv seçim gedir, gəlin onu gözləyək» demək daha yaxşıdır.
Kiçik sistemlərdə bu cür yoxlamaları prosesin yaddaşında həyata keçirmək olar. Daha ciddi infrastrukturlarda isə bu, MCP‑gateway və ya ayrıca rate‑limit xidməti səviyyəsinə çıxarılır.
3. Backpressure: istehlakçı çatmadıqda nə etməli
Rate‑limitlər nə qədər hadisə istehsal etmək istədiyimizi məhdudlaşdırır. Amma hətta səliqəli limitlərlə belə istehlakçının “boğulması” mümkündür: istifadəçinin mobil interneti zəifdir, brauzer vərəqi donub, ChatGPT həmin an güclü yüklənib.
Backpressure — istehlakçının çatmadığına sistem reaksiyasıdır. Məlumatları sonsuz yığmaq və gec‑tez OOM ilə yıxılmaq əvəzinə, şüurlu şəkildə:
- yavaşlayırıq;
- hadisələri aqreqasiya edirik;
- daha az vacibləri atırıq.
Təzyiq harada yaranır
GiftGenius üçün tipik ssenari belə görünə bilər. Worker hadisələri növbəyə yazır (məsələn, Redis Streams və ya sadəcə BD cədvəli), MCP‑server onları oxuyub SSE kanalına push edir. Müştəri yavaşdırsa (3G, köhnə noutbuk, bir sürü başqa vərəq), TCP buffer dolmağa başlayır, Node prosesi növbəni tam boşalda bilmir və nəhayət yaddaşda hadisələr yığır. Sonra isə tanış mənzərəni görürsünüz:
FATAL ERROR: Ineffective mark-compacts near heap limit
Şəbəkə səviyyəsində (TCP) backpressure artıq var, amma o, sizin domen subyektlərinizdən xəbərsizdir. O sadəcə deyir: «Hey, yavaşı, buffer dolub». Bizim vəzifə bunu MCP‑hadisələri səviyyəsində şərh etməkdir.
Limitli bufferləşdirmə və hadisələrin atılması
Proqres və statuslar üçün xoş bir özəllik var: bütün hadisələr eyni dərəcədə dəyərli deyil. İstifadəçi üçün son, aktual faiz önəmlidir, “51%, 52%, 53%, 54%” kimi bütün tarixçə yox. Deməli, hadisələrin bir qismini rahatlıqla drop edib yalnız sonuncunu göndərə bilərik.
Tutaq ki, worker‑lərdən proqres hadisələrini alan və hər bir jobId üçün bufferə qoyan qatımız var:
type ProgressEvent = { jobId: string; percent: number; message: string };
const progressBuffers = new Map<string, ProgressEvent[]>();
const MAX_BUFFER = 10;
function bufferProgress(event: ProgressEvent) {
const buffer = progressBuffers.get(event.jobId) ?? [];
buffer.push(event);
// buffer ölçüsünü məhdudlaşdırırıq
if (buffer.length > MAX_BUFFER) {
// yalnız son bir neçə hadisəni saxlayırıq
progressBuffers.set(event.jobId, buffer.slice(-MAX_BUFFER));
} else {
progressBuffers.set(event.jobId, buffer);
}
}
Ayrı bir taymer, məsələn hər 500 ms‑də bir, bufferə baxır və qalanları nəzərə almadan yalnız son hadisəni göndərir:
setInterval(() => {
for (const [jobId, buffer] of progressBuffers.entries()) {
if (!buffer.length) continue;
const last = buffer[buffer.length - 1];
sendProgressToClient(last); // SSE/MCP notification
progressBuffers.set(jobId, []); // təmizləyirik
}
}, 500);
Bu, conflation taktikasının nümunəsidir: bir neçə yeniləməni bir aktual yeniləmədə birləşdirmək. Proqres üçün — “qızıl” pattern.
«log» və ya partial_result tipli hadisələr üçün strategiya fərqli ola bilər. Orada hadisə itkisi çox vaxt yolverilməzdir: log mətnləri vacibdir, itən JSON “chunk”u isə məlumat strukturunu poza bilər. Bu hallarda siz:
- mesajı aqreqasiya edə bilərsiniz (bir neçə log sətrini bir paketdə birləşdirmək);
- və ya worker‑ə “log generasiyasını yavaşıt” tipli idarəedici siqnal göndərə bilərsiniz.
Asinxron sistemlərdə ikinci variant çətindir, amma barəsində düşünməyə dəyər.
Növbələrin dərinliyinin məhdudlaşdırılması
Backpressure yalnız göndərişdən əvvəl hadisə bufferi ilə məhdudlaşmır. Sisteminizdə bütün növbələrə baxmaq gərəkdir:
- worker‑i gözləyən tapşırıqlar növbəsi;
- worker ilə MCP‑server arasında hadisə növbəsi;
- server tərəfində axın kitabxanalarının daxilindəki bufferlər.
Hər növbə üçün məntiqli dərinlik limiti təyin etmək önəmlidir. Növbə dolarsa, ya müştərilərə “sistem yüklənib, xahiş edirik sonra yoxlayın” cavabını verirsiniz, ya da daha az vacib job‑ları atırsınız, ya da bir hissə ssenariləri “oflayn‑rejim”ə keçirirsiniz (məsələn, hesabat formalaşdırıb onu sonradan göndərilən link kimi verirsiniz).
Ayrıca maraqlı üsul — hadisə tiplərinin prioritetləşdirilməsi. Yüklənmə zamanı yalnız job.completed və job.failed göndərməyə başlaya, job.progress hadisələrinin prioritetini azalda və ya ümumiyyətlə söndürə bilərsiniz.
4. Axınların və hadisələrin monitorinqi
Ölçmələr olmadan rate‑limit və backpressure “sehrbazlığa” çevrilir. Axınların şübhəli dərəcədə çoxaldığını, hadisələrin ləngimə ilə gəldiyini və müştərilərin topa‑topa qopduğunu görmək lazımdır.
Axınlar adi HTTP‑sorğulardan fərqli davranır: onların müddəti dəqiqələrlə və saatlarla ölçülə bilər, buna görə də klassik “saniyədə sorğu sayı” və “orta gecikmə” metrikləri tam mənzərəni vermir.
Açar metriklər
SSE və ya HTTP/stream axınları üçün bir neçə göstərici qrupunu izləmək faydalıdır.
- Bağlantı metrikləri. Hazırda neçə aktiv SSE axını var? Bir bağlantı orta hesabla nə qədər “yaşayır”? Axınların neçə faizi səhv və ya timeout ilə bitir? Aktiv bağlantıların kəskin sıçrayışı potensial trafik fırtınası və ya resurs sızması (müştərilər bağlantıları bağlamır) deməkdir. Kəskin eniş — kütləvi qırılma (məsələn, şəbəkə problemi və ya serverdə kritik bug) deməkdir.
- Hadisə metrikləri. Bütün axınlar üzrə saniyədə nə qədər hadisə göndərirsiniz (EPS — events per second, yəni saniyədə hadisə sayı)? Hadisənin orta ölçüsü nədir? Payload seriyalaşdırma və ya validasiya səhvləriniz nə qədərdir? Birdən hadisə ölçülərinin artdığını görsəniz — ola bilər ki, kimsə job.progress daxilində qısa sətir əvəzinə hesabatın bütün mətnini göndərməyə başlayıb.
- Job metrikləri. Statuslara görə bölgü (pending, running, completed, failed, canceled), tapşırıq tipinə görə orta icra vaxtı, retry və ya dead‑letter‑ə düşən job‑ların faizi. Bu, problemin təkcə şəbəkə səviyyəsində yox, həm də worker‑lərdə olduğunu anlamağa kömək edir: xarici API yavaşlayıb, kütləvi səhvlər peyda olub.
- Backpressure metrikləri və sistem göstəriciləri. Axın sistemlərində tez‑tez komponentlər arasındakı buffer və növbələrin dərinliyinə, həmçinin istehlakçı yer açana qədər axının bloklu olduğu vaxtın faizinə baxılır. Növbələriniz demək olar ki, həmişə ağzınacan doludursa, bu, sistemin həddə yaxın olduğunun açıq siqnalıdır. Həmçinin axınla məşğul olan serverlərdə CPU və yaddaş kimi sistem göstəricilərini və şəbəkə səviyyəsində səhvləri/timeout‑ları izləmək vacibdir. Bəzən məhz MCP‑serverlə ChatGPT arasında şəbəkə buraxma qabiliyyəti dar boğaza çevrilir.
Cəmdə bu dörd qrup sizə üç suala cavab verir: hazırda neçə axın “yaşayır”, nə qədər məlumat ötürürsünüz, job‑lar necə davranır və sistemin harasında boğulma başlayır.
Nələri loglamaq lazımdır
Loglar — müşahidəolunurluğun ikinci sütunudur. Hadisələri və bağlantıları elə loglamaq vacibdir ki, sonra konkret bir job üçün tarixçə yığmaq mümkün olsun.
Adətən hər hadisə və axın üçün loglara bunları əlavə edirlər:
- jobId və/və ya eventId;
- userId və sessionId (multi‑tenant varsa);
- hadisə tipi (progress, completed, failed, resource.updated);
- kanal tipi (SSE və ya HTTP/stream);
- göndərmə timestamp‑i və mümkündürsə, hadisənin worker‑də yaranma timestamp‑i.
Beləcə lag‑ı hesablamaq olar: worker hadisəni yaratdığı vaxtla onun soketə yollandığı vaxt arasındakı fərq. Bu lag vaxtının artması backpressure problemlərinin yaxşı göstəricisidir.
Elə etmək lazımdır ki, loglar özləri yüklənmə mənbəyinə çevrilməsin. job.progress kimi yüksək tezlikli hadisələr üçün hər hadisəni loglamaq həmişə məntiqli deyil; sampling tətbiq etmək olar — ardıcıl hamısını yox, hər N‑ci hadisəni loglamaq — və ya statistik aqreqasiya etmək.
Kod səviyyəsində bu sadə helper kimi görünə bilər:
function logEvent(event: {
type: string;
jobId: string;
userId?: string;
channel: "sse" | "http-stream";
payload: unknown;
}) {
console.info({
...event,
timestamp: new Date().toISOString(),
});
}
Real layihədə bunu structured logging kitabxanasına bürüyəcəksiniz, amma ideya eynidir: hər qeyddə maksimum faydalı kontekst.
5. Alertlər və deqradasiya siyasətləri
Artıq metrik və loglarınız olanda növbəti addım — alertləri qurmaq və sistem yüklənəndə onun necə “deqradasiya” etməli olduğunu düşünməkdir. Fikir budur ki, qəfil yıxılmaqdan isə dürüst şəkildə bir az “pis” işləmək daha yaxşıdır.
Alert nümunələri
GiftGenius üçün bir neçə tipik situasiyanı izləmək məntiqlidir.
Birincisi, aktiv axınların anormal sayı. Adətən onlarla aktiv SSE bağlantısı varkən birdən minlərlə olursa, nə baş verdiyini anlamağa dəyər. Bəlkə populyarlaşmısınız, bəlkə də — bug var və bağlantılar bağlanmır.
İkincisi, job faktiki başa çatması ilə müştərinin job.completed alması arasında gecikmə. Bu gecikmə həddi keçməyə başlayırsa (deyək, 5–10 saniyə), deməli, hardasa worker ilə müştəri arasında hadisələr yığılır və ya bağlantılar ilişir.
Üçüncüsü, job.failed və ya job.canceled payının uğurlulara nisbətən yüksək olması. Səbəb həm worker‑də ola bilər (xarici API sıradan çıxıb, yeni bug), həm də istifadəçinin gecikmələrə daha həssas olması (tapşırıqları daha tez‑tez ləğv edirlər).
Nəhayət, bağlantı səhvləri və stream qırılmalarının artması: qeyri‑standart disconnect sayı yüksəlirsə, şəbəkə və ya müştəri tərəfində problemlər ola bilər və fallback ssenarilərini düşünmək dəyərlidir.
Deqradasiya pattern‑ləri
Sistem yükləndikdə “resurs qənaəti rejimi”ni aktivləşdirmək olar. Bu, hər şeyə 500 cavabı qaytarmaqdan daha yaxşıdır.
Ən çox rast gəlinən pattern — hadisə tezliyinin adaptiv tənzimlənməsi. Əgər event‑rate (saniyədə hadisə sayı) adi haldan on dəfə qalxıbsa və növbələrdə lag artmağa başlayırsa, proqres hadisələrinin tezliyini azaldın. Hər 1 % idi — 10 % edin. Hər 500 ms idi — 2–3 saniyəyə salın. İstifadəçi həddən artıq dəqiq proqressiz də rahat yaşayar, amma tam donmuş UI ilə — yox.
Daha az vacib hadisələr üçün — məsələn, məhsul feed‑inin arxa planda yenilənməsinə dair resource.updated — sistem yük altındaykən göndərişi müvəqqəti söndürmək olar.
Daha bir üsul — bəzi ssenariləri axınlardan periodik polling‑ə keçirməkdir. Əgər SSE kanalları çökməyə başlayırsa, MCP‑server vidcetə system.overloaded kimi sistem hadisəsi göndərə, vidcet isə “job statusunu N saniyədən bir REST‑endpoint vasitəsilə soruşuram” strategiyasına keçə bilər.
6. GiftGenius üçün kiçik praktik fraqment
Bütününü birləşdirmək üçün təsəvvür edək ki, artıq bunlar var:
- MCP‑tool startGiftSearch, job yaradır və jobId qaytarır;
- axtarışı icra edib event/progress və event/completed göndərən worker;
- vidcetin Next.js‑də qoşulduğu SSE‑endpoint /api/events/[userId].
“Hadisə fırtınası”na qarşı sadə müdafiə səviyyəsi və minimal monitorinq əlavə edək.
Proqresi addım və vaxta görə məhdudlaşdırma
Worker‑də yuxarıda müzakirə etdiyimiz kimi throttling və conflation əlavə edirik. İndi hadisələr yarım saniyədən tez olmayaraq və ən azı 5 % dəyişəndə göndərilir.
Aktiv axınların uçotu
SSE endpoint‑ində istifadəçi üzrə sayğacı saxlayırıq:
const activeStreams = new Map<string, number>();
const STREAM_LIMIT = 3;
function canOpenMoreStreams(userId: string) {
const current = activeStreams.get(userId) ?? 0;
return current < STREAM_LIMIT;
}
function registerSseClient(userId: string, controller: ReadableStreamDefaultController) {
const current = activeStreams.get(userId) ?? 0;
activeStreams.set(userId, current + 1);
// burada controller-i hansısa struktura saxlayırsınız ki,
// sonradan bu axına hadisələri yaza biləsiniz
}
function unregisterSseClient(userId: string) {
const current = activeStreams.get(userId) ?? 1;
activeStreams.set(userId, Math.max(0, current - 1));
}
Server activeStreams.size üzrə metrikləri əlavə olaraq Prometheus/Grafana və ya istənilən başqa monitorinq sisteminə göndərə bilər.
Event‑rate üçün ən sadə metrika
Başlanğıc üçün nə qədər hadisə göndərdiyimizi heç olmasa təxmini sayaq:
let eventsSentLastMinute = 0;
function sendProgressToClient(ev: ProgressEvent) {
// ... seriyalaşdırma və SSE axınına yazı
eventsSentLastMinute++;
}
setInterval(() => {
console.info({
metric: "events_per_minute",
value: eventsSentLastMinute,
timestamp: new Date().toISOString(),
});
eventsSentLastMinute = 0;
}, 60_000);
Zamanla bunu normal sayğaclar və alertlərlə əvəz edə bilərsiniz, amma start nöqtəsi kimi — pis deyil.
Yuxarıdakılardan: limitlər, backpressure, metriklər/alertlər və adekvat UX‑fallback birlikdə GiftGenius‑unuzu “demo üçün demo”dan çıxarıb real trafik fırtınalarına dözümlü edir. Növbəti modullarda, gateway, production arxitektura və tam müşahidəolunurluq barədə danışanda bu pattern‑lər işimizə yarayacaq.
7. Axınlar, rate‑limitlər və monitorinq ilə işləyərkən tipik səhvlər
Səhv № 1: axın sayına və hadisə tezliyinə limitlərin olmaması.
Tərtibatçılar “gözəl olsun” deyə SSE əlavə ediblər, worker‑lər hər emal olunan obyekt üçün proqres göndərir və hər şey demoda işləyir. Amma ilk real istifadəçi sıçrayışında server resursların böyük hissəsini minlərlə xırda hadisənin seriyalaşdırılmasına və ötürülməsinə sərf etməyə başlayır, ChatGPT‑də UI isə slayd‑şouya çevrilir.
Səhv № 2: “hər şeyi” limitsiz bufferləşdirməyə cəhd.
Koddakı “çıxmayan hadisələr” üçün limitsiz massiv müştəri bərpa olunana qədər böyüyür. Spoiler: bərpa olunmur, server daha tez ölür. Hər bir bufferin sərt maksimumu olmalı, dolma məntiqi isə aydın şəkildə təsvir edilməlidir.
Səhv № 3: bütün hadisə tiplərinə eyni münasibət.
Proqresi aqreqasiya edib atmaq olar (son faiz hərəkət tarixçəsindən daha önəmlidir). Loglar və partial nəticələrlə bunu etmək olmaz — bir “chunk”un itkisi zədələnmiş məlumat deməkdir. Sistemi layihələndirərkən hadisələri öncədən önəmlilik qruplarına bölün və hər qrup üçün yüklənmə strategiyası fikirləşin.
Səhv № 4: müşahidəolunurluğun olmaması.
Aktiv axınlar üzrə heç bir metrika, event‑rate uçotu yoxdur, loglarda isə yalnız “nəsə səhv getdi”. Belə vəziyyətdə problemləri yalnız istifadəçi rəylərindən və CPU yük qrafikindən öyrənirsiniz. Heç olmasa jobId və eventId üzrə baza metrikləri və logları qurmaq — lüks deyil, zərurətdir.
Səhv № 5: deqradasiyanı nəzərə almayan sərt UX.
Vidcet və GPT təlimatları axının həmişə əlçatan olacağını, proqresin “real vaxtda” yenilənəcəyini, partial nəticələrin ssenariyə uyğun gələcəyini fərz edir. İlk şəbəkə problemlərində istifadəçi “donmuş” proqres barını görür və heç bir izah almır. UX‑də dürüst fallback qoymaq qat‑qat yaxşıdır: «Hazırda canlı yeniləmə ilə bağlı problemlər var, mən yenə də axtarışı davam etdirəcəyəm və bitirəndə xəbər verəcəyəm» — və daha seyrək yeniləmələrə və ya pollinqə keçmək.
Səhv № 6: “istifadəçilərimiz çoxlu paralel tapşırıq yaratmaz” etimadı.
Təcrübə göstərir ki, paralel job və axın sayını məhdudlaşdırmasanız, kimsə hökmən beş vərəq açacaq, hər birində “maksimum” hədiyyə seçimini işə salacaq və qəhvə içməyə gedəcək. Production‑da “bəlkə keçər” ideyası demək olar ki, həmişə alertlərin gurultusu altında monitorinqlə tanışlıqla bitir.
GO TO FULL VERSION