الـ Concurrency Limits والـ Bulkheads: dependency بطيئة ما توقعش الـ app كله
recommendations بطيئة خدت كل الـ connections، والـ checkout اللي بياخد ملي تانية بقى أربع تواني. بنفهم Little's law، وليه الـ pool المشترك بيعمل starvation، والـ bulkheads (حد منفصل لكل dependency أو route)، والطابور المحدود والـ queue timeout، والـ load shedding بـ 503 و Retry-After، والـ adaptive concurrency والـ priorities. والتحدي: limiter.js قصاد أربعتاشر حالة.
نص شرح المعلم والكود الذي كتبه ونتيجة تشغيله، بنفس ترتيب الدرس.
أهلًا بيك. في الدرس اللي فات شفنا إن لما الـ load يعدّي الـ knee، الـ requests بتستنى في طابور، وكله بيبطّأ. النهارده هنشوف حاجة أوحش: جزء واحد بطيء في الـ app بيوقّع الأجزاء التانية كلها. db dot js: pool واحد للـ database، فيه عشر connections بس. وده طبيعي، أي database ليها حد للـ connections. وفيه query اسمها recs، بتجيب recommendations، وبتاخد تانية كاملة، زي analytics تقيلة. و query اسمها checkout، سريعة أوي. server dot js: route لكل واحدة، والاتنين بيستخدموا نفس الـ pool من غير أي حدود. و load dot js: أربعين user فتحوا صفحة فيها recommendations في نفس الوقت، وبعدها بشوية خمسة users بيدفعوا. نشغّل.
// load.js: أربعين user فتحوا صفحة فيها recommendations في نفس الوقت، وخمسة بيدفعوا
const B = "http://localhost:3000";
const t = async (p) => { const s = performance.now(); const r = await fetch(B + p); await r.text(); return { status: r.status, ms: performance.now() - s }; };
await t("/checkout?order=0"); // warm-up
const recsP = Array.from({ length: 40 }, (_, i) => t(`/recs?user=u${i}`));
await new Promise((r) => setTimeout(r, 100));
const pays = [];
for (let i = 1; i <= 5; i++) pays.push(await t(`/checkout?order=${i}`));
const rs = await Promise.all(recsP);
const count = (s) => rs.filter((r) => r.status === s).length;
console.log(`checkout: ${pays.map((p) => `${p.status} في ${p.ms.toFixed(0)}ms`).join(" | ")}`);
console.log(`recs: ${count(200)} رجعوا 200، و ${count(503)} رجعوا 503 | أبطأ واحد ${Math.max(...rs.map((r) => r.ms)).toFixed(0)}ms`);المخرجات
$ node server.js & S=$!; sleep 1.5; node load.js; kill $S on 3000 checkout: 200 في 3914ms | 200 في 2ms | 200 في 2ms | 200 في 2ms | 200 في 2ms recs: 40 رجعوا 200، و 0 رجعوا 503 | أبطأ واحد 4040ms
أول checkout خد حوالي أربع تواني. query بتاخد ملي تانية واحدة، والـ user اللي بيدفع فلوس استنى أربع تواني. والـ recs كلها نجحت، بس أبطأ واحدة خدت أربع تواني برضه. إيه اللي حصل؟ الأربعين recs دخلوا الأول. عشرة خدوا الـ connections، والتلاتين التانيين وقفوا في طابور الـ pool. والـ checkout جه وقف ورا التلاتين دول. فاستنى أربع دفعات من الـ recs، كل دفعة تانية. ده اسمه starvation: حاجة مش مهمة أكلت الـ resource المشترك، والحاجة المهمة جاعت. وفي الحقيقة الموضوع بيبقى أوحش: الـ recs بتستنى أكتر، والـ client بيعمل timeout ويعيد، فالطابور يكبر، ولحد ما الـ app كله يبان كأنه واقع. وده اسمه cascading failure.
علشان نفهم ليه، فيه قانون بسيط اسمه Little law. عدد الحاجات اللي في النص في أي وقت، هو نفسه المعدل اللي بتدخل بيه، مضروب في الوقت اللي كل واحدة بتقعده. زي: لو عندك مِيّتين request في التانية، وكل واحد بياخد خمسين ملي تانية، يبقى في المتوسط عشرة requests شغّالين في نفس الوقت. دلوقتي الـ recs: لو جالك أربعين في التانية، وكل واحدة بتاخد تانية، محتاج أربعين connection. عندك عشرة بس. يبقى الطابور هيكبر تلاتين كل تانية، ومش هيقف أبدًا. والدرس المهم: اللي بيخلص مش الـ requests في التانية، اللي بيخلص هو الـ concurrency: connections، و threads، و memory. ولما dependency تبطّأ، الـ latency بتزيد، فالـ concurrency بتزيد معاها، حتى لو الـ traffic زي ما هو.
الحل الأول: bulkheads. الكلمة جاية من المراكب: جسم المركب متقسم أوض، كل أوضة مقفولة. لو أوضة اتخرمت، الغرق بيفضل في الأوضة دي بس، والمركب يكمّل. في الـ backend: كل dependency أو route ليه حد منفصل. الـ recs ما تقدرش تاخد أكتر من تلات connections من العشرة، والباقي متساب للـ checkout. فلو الـ recs بطّأت، هي بس اللي بتتضرّ. وفيه أكتر من طريقة: limiter في الـ code قبل كل route أو كل dependency، وده اللي هنكتبه. أو pool منفصل لكل نوع مهام، زي pool للـ analytics و pool للـ checkout، أو حتى read replica للتقيل. أو process أو service منفصلة خالص للشغل التقيل. والحد ده تحسبه بـ Little law: الـ checkout محتاج كام في الـ peak، وسيب له مكانه.
الحل التاني: الطابور لازم يبقى ليه حد. طابور من غير حد ده أوحش حاجة. الـ requests بتستنى، والـ user بيزهق ويقفل الصفحة، والـ server لسه شغّال على request محدش مستنيه. وكل اللي وراه بيستنى أكتر. فبنعمل حاجتين: maxQueue: لو الطابور مليان، ارفض على طول. ده اسمه load shedding: بنرمي جزء من الـ load بإيدينا، علشان الباقي يتخدم كويس. queueTimeoutMs: لو حد استنى في الطابور أكتر من كده، ارفضه. لأنه غالبًا الـ client عمل timeout خلاص. والرفض بيبقى five oh three، ومعاه header اسمه Retry-After، بيقول للـ client يستنى كام تانية قبل ما يحاول تاني. الفكرة: رد سريع بـ لأ أحسن بكتير من رد بطيء بعد خمس تواني. الـ client يقدر يعرض حاجة تانية، أو يعيد بعدين، أو يروح لـ server تاني.
وكام حاجة كمان في الحقيقة: الأرقام اللي ما بتتغيرش صعب تختارها، والـ load بيتغير. فيه حاجة اسمها adaptive concurrency: الـ limiter بيقيس الـ latency بنفسه، ولو بدأت تزيد يقلّل الحد، ولو كويسة يزوّده شوية بشوية. زي TCP congestion control بالضبط، والطريقة دي اسمها AIMD. ومكتبة Netflix اسمها concurrency limits مشهورة في ده. priorities: لو لازم ترمي حاجة، ارمي الأقل أهمية الأول. الـ recs قبل الـ checkout، والـ background jobs قبل الـ users. per-tenant limits: علشان customer واحد كبير ما ياخدش الـ server كله، زي الـ rate limiting اللي عملناه قبل كده. الحد على مستوى الـ proxy كمان، زي nginx. وده فرقه عن الـ rate limiting: الـ rate limit بيعد requests في الدقيقة لكل user. الـ concurrency limit بيعد كام شغّال دلوقتي، وبيحمي الـ resources نفسها.
server dot js الجديد: limiter للـ recs، تلاتة في نفس الوقت، وطابور ستة، و timeout تانية ونص. و limiter للـ checkout ستة. يعني الاتنين مع بعض تسعة، تحت العشرة بتوع الـ pool. وفيه route اسمه stats. التحدي: اكتب limiter dot js. التفاصيل كلها في الكومنت، و test dot js فيه أربعتاشر حالة.
limiter.js: createLimiter بـ concurrency وطابور FIFO محدود بـ maxQueue و queueTimeoutMs، وبيرفض بـ LimitError (OVERLOADED أو QUEUE_TIMEOUT)، و stats، و limitMiddleware بيرجّع 503 و Retry-After، و littlesLaw.
الحل. run: لو فيه slot فاضي نشغّل على طول. لو الطابور مليان نرفض على طول من غير ما نستنى. غير كده ندخل الطابور، ومعانا timer. الترتيب في start مهم: fn، وبعدين finally بيسيب الـ slot ويبدأ اللي عليه الدور، وبعدين بس الـ Promise يتحل. لما الـ timer يضرب، بنشيل نفسنا من الطابور ونرفض. ولما ييجي دورنا قبل الـ timeout، بنعمل clearTimeout. والـ middleware: الـ slot بيفضل محجوز لحد ما الـ response يعمل close، فالـ handler كله، بالـ query بتاعته، جُوّه الحد. نشغّل load dot js تاني.
// limiter.js: concurrency limiter بطابور محدود و timeout، و middleware بيرجّع 503، و Little's law
export class LimitError extends Error {
constructor(code) { super(code); this.code = code; }
}
export function createLimiter({ concurrency, maxQueue = 0, queueTimeoutMs = Infinity }) {
let active = 0, rejected = 0;
const queue = []; // كل واحد: { start, timer }
const next = () => {
active--;
const w = queue.shift();
if (w) { clearTimeout(w.timer); active++; w.start(); }
};
const run = (fn) => new Promise((resolve, reject) => {
const start = () => Promise.resolve().then(fn).finally(next).then(resolve, reject);
if (active < concurrency) { active++; return start(); }
if (queue.length >= maxQueue) { rejected++; return reject(new LimitError("OVERLOADED")); }
const w = { start };
if (Number.isFinite(queueTimeoutMs)) {
w.timer = setTimeout(() => {
queue.splice(queue.indexOf(w), 1);
rejected++;
reject(new LimitError("QUEUE_TIMEOUT"));
}, queueTimeoutMs);
}
queue.push(w);
});
return { run, stats: () => ({ active, queued: queue.length, rejected }) };
}
// الـ handler بيشتغل جُوّه الـ limiter، والـ slot بيتساب لما الـ response يخلص
export const limitMiddleware = (limiter, { retryAfterSec = 1 } = {}) => (req, res, next) => {
limiter
.run(() => new Promise((done) => { res.on("close", done); next(); }))
.catch((e) => {
if (!(e instanceof LimitError)) return next(e);
if (res.headersSent) return;
res.set("Retry-After", String(retryAfterSec)).status(503).json({ error: e.code });
});
};
// L = λ × W: عدد الشغل اللي في النص = المعدل في التانية × الوقت بالتواني
export const littlesLaw = ({ rps, latencyMs }) => Math.ceil((rps * latencyMs) / 1000);المخرجات
$ node server.js & S=$!; sleep 1.5; node load.js; kill $S on 3000 checkout: 200 في 8ms | 200 في 2ms | 200 في 2ms | 200 في 2ms | 200 في 2ms recs: 6 رجعوا 200، و 34 رجعوا 503 | أبطأ واحد 2051ms
الـ checkout دلوقتي كام ملي تانية بس، رغم إن الأربعين recs شغّالين. الـ bulkhead شغّال. الـ recs: ستة نجحوا، تلاتة في الأول وتلاتة من الطابور، والتلاتة اللي بعدهم استنوا أكتر من تانية ونص فاترفضوا، والباقي اترفض على طول لأن الطابور كان مليان. يعني رمينا أغلب الـ recs، وده مقصود. الصفحة هتبان من غير recommendations، أو بـ recommendations قديمة من الـ cache، والـ user يكمّل يدفع. أحسن بكتير من إن كله يقف. ونشغّل test dot js.
المخرجات
$ node server.js & S=$!; sleep 1.5; node test.js; kill $S
on 3000
✅ concurrency اتنين: عمره ما عدّى اتنين، والستة خلصوا max 2
✅ الطابور مليان ← OVERLOADED على طول
✅ stats: active واحد و queued واحد و rejected واحد {"active":1,"queued":1,"rejected":1}
✅ استنى أكتر من queueTimeoutMs ← QUEUE_TIMEOUT 50ms
✅ بعد الـ timeout الطابور فاضي
✅ الطابور FIFO 1,2,3,4
✅ fn بتعمل throw ← نفس الـ error، والـ slot بيتساب
✅ Little's law: مِيّتين في التانية × خمسين ms ← عشرة، و سبعة × مِيّة وخمسين ← اتنين
✅ checkout وقت الـ flood: الخمسة 200 وكل واحد أقل من تلتمية ms 6 2 1 1 2
✅ recs: من تلاتة لتسعة نجحوا، والباقي 503 6 / 34
✅ الـ 503 فيه Retry-After اتنين و error code
✅ فيه OVERLOADED و QUEUE_TIMEOUT الاتنين
✅ الـ OVERLOADED رجع بسرعة، أقل من مِيّتين ms
✅ بعد الـ flood: recs active صفر و queued صفر، و pool ما عدّاش عشرة {"recs":{"active":0,"queued":0,"rejected":34},"checkout":{"active":0,"queued":0,"rejected":0},"pool":{"total":4,"waiting":0}}
14/14كله نجح. بس فيه سؤال: الـ recs كانت بتاخد تانية، بس لو dependency بقت بتاخد دقيقة، أو ما بتردش خالص؟ الـ slots هتفضل محجوزة. الدرس الجاي: timeouts، و retries بـ backoff و jitter، و circuit breakers. إزاي تبطّل تستنى dependency واقعة، وإزاي تعيد من غير ما توقعها أكتر.
// server.js: bulkheads: كل route ليه limiter، والـ recs ما تقدرش تاخد أكتر من تلات connections من العشرة
import express from "express";
import { recs, checkout, pool } from "./db.js";
import { createLimiter, limitMiddleware } from "./limiter.js";
const recsLimit = createLimiter({ concurrency: 3, maxQueue: 6, queueTimeoutMs: 1500 });
const payLimit = createLimiter({ concurrency: 6, maxQueue: 50, queueTimeoutMs: 3000 });
const app = express();
app.get("/recs", limitMiddleware(recsLimit, { retryAfterSec: 2 }), async (req, res) => res.json((await recs(req.query.user)).rows[0]));
app.get("/checkout", limitMiddleware(payLimit), async (req, res) => res.json((await checkout(Number(req.query.order))).rows[0]));
app.get("/stats", (req, res) => res.json({ recs: recsLimit.stats(), checkout: payLimit.stats(), pool: { total: pool.totalCount, waiting: pool.waitingCount } }));
app.listen(3000, () => console.log("on 3000"));// db.js: pool واحد لكل الـ app: عشر connections بس (زي أي database حقيقية: الـ connections ليها حد)
import pg from "pg";
export const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL, max: 10 });
// recommendations: query تقيلة (analytics) بتاخد تانية. checkout: query سريعة
export const recs = (user) => pool.query("SELECT pg_sleep(1), $1::text AS user, 'منتجات مقترحة' AS items", [user]);
export const checkout = (order) => pool.query("SELECT $1::int AS order_id, 'paid' AS status", [order]);import { LimitError, createLimiter, littlesLaw } from "./limiter.js";
let ok = 0, all = 0;
const check = (name, cond, extra = "") => { all++; if (cond) ok++; console.log(cond ? "✅" : "❌", name, extra); };
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
const B = "http://localhost:3000";
const err = (p) => p.then(() => null, (e) => e);
// unit: الـ limiter لوحده
{
const l = createLimiter({ concurrency: 2, maxQueue: 10 });
let now = 0, max = 0;
const job = async () => { now++; max = Math.max(max, now); await sleep(40); now--; return "تمام"; };
const out = await Promise.all(Array.from({ length: 6 }, () => l.run(job)));
check("concurrency اتنين: عمره ما عدّى اتنين، والستة خلصوا", max === 2 && out.every((x) => x === "تمام"), `max ${max}`);
}
{
const l = createLimiter({ concurrency: 1, maxQueue: 1 });
const a = l.run(() => sleep(60)), b = l.run(() => sleep(10));
const t0 = performance.now();
const e = await err(l.run(() => "مش هيشتغل"));
check("الطابور مليان ← OVERLOADED على طول", e instanceof LimitError && e.code === "OVERLOADED" && performance.now() - t0 < 20);
check("stats: active واحد و queued واحد و rejected واحد", JSON.stringify(l.stats()) === JSON.stringify({ active: 1, queued: 1, rejected: 1 }), JSON.stringify(l.stats()));
await Promise.all([a, b]);
}
{
const l = createLimiter({ concurrency: 1, maxQueue: 5, queueTimeoutMs: 50 });
const a = l.run(() => sleep(200));
const t0 = performance.now();
const e = await err(l.run(() => "متأخر"));
const waited = performance.now() - t0;
check("استنى أكتر من queueTimeoutMs ← QUEUE_TIMEOUT", e?.code === "QUEUE_TIMEOUT" && waited >= 45 && waited < 150, `${waited.toFixed(0)}ms`);
check("بعد الـ timeout الطابور فاضي", l.stats().queued === 0);
await a;
}
{
const l = createLimiter({ concurrency: 1, maxQueue: 10 });
const order = [];
await Promise.all([1, 2, 3, 4].map((i) => l.run(async () => { await sleep(5); order.push(i); })));
check("الطابور FIFO", order.join() === "1,2,3,4", order.join());
}
{
const l = createLimiter({ concurrency: 1 });
const e = await err(l.run(() => { throw new Error("وقع"); }));
const v = await l.run(() => 42);
check("fn بتعمل throw ← نفس الـ error، والـ slot بيتساب", e?.message === "وقع" && v === 42 && l.stats().active === 0);
}
check("Little's law: مِيّتين في التانية × خمسين ms ← عشرة، و سبعة × مِيّة وخمسين ← اتنين", littlesLaw({ rps: 200, latencyMs: 50 }) === 10 && littlesLaw({ rps: 7, latencyMs: 150 }) === 2);
// integration: recs بتغرق، و checkout لازم يفضل سريع
await fetch(`${B}/checkout?order=0`);
const t = async (p) => { const s = performance.now(); const r = await fetch(B + p); return { status: r.status, ms: performance.now() - s, ra: r.headers.get("retry-after"), body: await r.json() }; };
const flood = Promise.all(Array.from({ length: 40 }, (_, i) => t(`/recs?user=t${i}`)));
await sleep(100);
const pays = [];
for (let i = 1; i <= 5; i++) pays.push(await t(`/checkout?order=${i}`));
const rs = await flood;
che
…03 / دروس المسار (122)
- 01أهلًا بيك: يعني إيه backend، والكورس ده ماشي إزاي
- 02الملفات والفولدرات والـ terminal: تتحرك على جهازك زي المبرمجين
- 03Node وأول برنامج: تشغّل وتقرا رسالة الخطأ
- 04القيم والمتغيرات والأنواع: const و let و typeof
- 05القرارات والتكرار: if و === والـ truthy والـ loops
- 06الـ functions: parameters و return والـ arrow functions والـ scope
- 07الـ objects والـ arrays: destructuring و spread و map و filter و reduce
- 08JSON والنصوص والتواريخ: اللغة اللي الـ backend بيتكلم بيها
- 09الـ callbacks والـ closures وأول لمسة async: setTimeout
- 10الـ classes والـ errors: throw و try/catch و stack trace
- 11git: تحفَظ كل خطوة وترجعلها، وما تسرّبش أسرارك
- 12ESM و CommonJS و package exports: Node بيلاقي الـ modules إزاي
- 13الـ Promises و async/await: sequential و parallel والأخطاء والإلغاء
- 14الـ event loop والـ microtasks: Node بيعمل كل حاجة بـ thread واحد إزاي
- 15الـ Streams والـ Backpressure: ملفات أكبر من الـ memory
- 16الـ File System والـ paths: قراية وكتابة صح، ومن غير path traversal
- 17الـ Buffers والبيانات الـ binary: الـ bytes من جُوّه
- 18Crypto APIs والأسرار: random و hash و HMAC و AES-GCM
- 19الـ Worker Threads: شغل CPU تقيل من غير ما توقف الـ server
- 20الـ Errors على مستوى الـ process: operational و programmer و crash-only
- 21الـ Node test runner والـ debugging: tests من غير مكتبات
- 22HTTP من جُوّه: الـ methods والـ status codes والـ headers
- 23Express والـ Routing: الـ params والـ query والترتيب والـ Router
- 24Express 5: إيه اللي اتغيّر، وإزاي تنقل مشروع قديم
- 25الـ Middleware ودورة حياة الـ request جُوّه Express
- 26Validation للمدخلات بـ Zod: ما تصدّقش أي حاجة جاية من برة
- 27تصنيف الأخطاء و Problem Details: شكل واحد لكل الـ errors
- 28الـ CORS والـ Cookies: المتصفح بيحمي المستخدم إزاي
- 29رفع الملفات وحدود الحجم: multer من غير ثغرات
- 30الـ Realtime: Server-Sent Events و WebSockets
- 31OpenAPI والـ API Versioning: عقد مكتوب، وتغيير من غير ما تكسر حد
- 32PostgreSQL: الـ DDL وأنواع البيانات الصح لكل عمود
- 33الـ Constraints: PK و FK و UNIQUE و CHECK — الـ database بتحمي نفسها
- 34الـ Normalization والـ ERD: تقسّم البيانات صح من أول يوم
- 35الـ JOINs والتجميع: INNER و LEFT و GROUP BY و HAVING و window functions
- 36JSONB في PostgreSQL: إمتى تستخدمه، وإزاي تسأله وتعمله index
- 37الـ Indexes من جُوّه: B-tree و GIN و BRIN
- 38Partial و Covering indexes: indexes أصغر وأسرع
- 39الـ Pagination بالـ Keyset: ليه OFFSET بيبطّأ وبيكرر
- 40Full Text Search في Postgres: بحث بالكلمات، بالعربي والإنجليزي
- 41EXPLAIN ANALYZE والـ Planner: اقرا الـ plan وصلّح الـ query
- 42الـ Transactions بـ node-postgres: كله أو ولا حاجة
- 43الـ MVCC ومستويات الـ Isolation: transactions كتير في نفس الوقت
- 44الـ Locks والـ Deadlocks: مين مستني مين
- 45SKIP LOCKED و Job Leasing: Postgres كـ job queue
- 46Row Level Security والـ Multi-tenancy: كل عميل يشوف بياناته بس
- 47Migrations من غير downtime: expand و backfill و contract
- 48الـ Replication والـ Read Replicas: نسخ حية من الـ database
- 49الـ Connection Pooling و PgBouncer: connections أقل، requests أكتر
- 50الـ Partitioning والـ VACUUM والمراقبة: Postgres على المدى الطويل
- 51Redis وأنواع البيانات: strings و hashes و lists و sets و sorted sets
- 52Cache-aside والـ TTL: Redis قدام الـ database
- 53الـ Cache invalidation والـ Stampede: لما الـ key الشهير يموت
- 54Lua والـ Atomicity في Redis: كام أمر كأنهم أمر واحد
- 55الـ Rate Limiting في Redis: fixed window و sliding window و token bucket
- 56الـ Sessions في Redis: تسجيل دخول تقدر تلغيه في أي وقت
- 57Redis Streams والـ Consumer Groups: log بيتوزع على workers
- 58Pub/Sub و BullMQ: إشارات بين الـ instances، وطوابير شغل محترمة
- 59Redis لما يقع: الـ persistence (RDB و AOF) والـ replication
- 60Redis في الإنتاج: الـ ACLs والـ Cluster والمراقبة
- 61تخزين الـ Passwords بـ Argon2id: صح من أول مرة
- 62Session Fixation والـ Rotation: id جديد مع كل صلاحية جديدة
- 63الـ Cookie Flags والـ CSRF: المتصفح بيبعت الـ cookie، فلازم تتأكد مين اللي طلب
- 64الـ XSS والـ Content Security Policy: ما تخليش النص يتحوّل لـ code
- 65الـ OAuth و OpenID Connect و PKCE: login بـ Google من غير ما تشوف الـ password
- 66التأكد من الـ JWT صح: التوقيع والـ claims والـ scopes
- 67الـ BOLA و BFLA: الـ token السليم مش معناه إن الطلب مسموح
- 68الـ RBAC و ABAC والملكية: policy واحدة بدل ifs متفرقة
- 69الـ MFA والـ recovery: التاني factor اللي بجد
- 70الـ Passkeys و WebAuthn: login من غير password وضد الـ phishing
- 71الـ Threat Modeling بـ STRIDE: فكّر زي المهاجم قبل ما تكتب code
- 72الـ SQL Injection والـ Parameterization: الـ data ما تبقاش code
- 73الـ SSRF والـ Egress: ما تخليش الـ server بتاعك يزور الشبكة الداخلية
- 74الـ Security Headers والـ TLS: كل response يقول للـ browser يحمي المستخدم إزاي
- 75توقيع الـ Webhooks والـ Replay: الـ webhook ده جاي فعلًا من Stripe؟
- 76تغيير الأسرار والـ HMAC: إزاي تغيّر مفتاح من غير ما كل حاجة تقع
- 77سلسلة التوريد والـ SBOM: إنت واثق في ألف package ما تعرفهمش؟
- 78الـ Audit والـ Privacy Logs: سجّل مين عمل إيه، من غير ما تسجّل الأسرار
- 79اختبار الأمان و OWASP ASVS: الأمن جُوّه الـ CI، مش audit آخر السنة
- 80الـ Prototype Pollution والـ Resource DoS: request واحد يخلّي الكل admin أو يوقّع الـ server
- 81الـ SLI والـ SLO والـ Error Budget: إمتى تصحّي الـ on-call وإمتى تسيبه نايم
- 82الـ Event Loop Delay والـ ELU: لما Node نفسه يتخنق
- 83الـ Worker Threads والـ CPU Profiling: الشغل التقيل بره الـ event loop، والوقت راح فين
- 84الـ Memory والـ GC والـ Leaks: الـ process اللي بيكبر لحد ما يقع
- 85الـ N+1 Queries والـ DataLoader: صفحة واحدة بمِيّتين query
- 86الـ HTTP Caching والـ Compression: أسرع request هو اللي ما بيوصلش
- 87الـ Load Testing والـ Soak Testing: الـ server بيستحمل قد إيه بجد
- 88الـ Concurrency Limits والـ Bulkheads: dependency بطيئة ما توقعش الـ app كلهانت هنا
- 89الـ Timeouts والـ Retries والـ Circuit Breakers: إزاي تتعامل مع dependency بطيئة أو واقعة
- 90OpenTelemetry والـ Distributed Tracing: الـ request راح فين وضاع وقته فين
- 91Docker Layers والـ Build Context: ليه الـ build بياخد دقيقة وفيه الـ .env بتاعك
- 92Multi-stage Builds و Non-root: image صغيرة ومن غير root
- 93Docker Compose والـ Networks: الـ services بتلاقي بعض إزاي
- 94Docker Volumes: الـ data بتتحفَظ فين
- 95Healthcheck و Restart و Resource Limits: running مش معناها شغّال
- 96BuildKit والـ Build Secrets: الـ token ما يدخلش الـ image
- 97Reverse Proxy و TLS: اللي واقف قدام الـ app
- 98Multi-arch Images والـ Native Modules: اشتغلت عندي
- 99CI/CD و Rollback و Canary: الـ deploy يبقى ممل
- 100Kubernetes من الأول: Pods و Deployments و Services و Probes
- 101Modular Monolith و DDD: حدود واضحة من غير network
- 102Transactional Outbox و Inbox: الـ event ما يضيعش وما يتنفذش مرتين
- 103Sagas: عملية واحدة على تلات services من غير transaction واحدة
- 104CQRS و Event Sourcing: الـ events هي الحقيقة
- 105الـ Queues والـ Brokers: BullMQ و RabbitMQ و Kafka و SQS
- 106Realtime على أكتر من instance: Redis pub/sub و presence و resume
- 107الـ Object Storage والـ Media: presigned URLs و uploads مباشرة
- 108التكامل مع الـ Email والـ Search: retries و webhooks و indexes
- 109GraphQL و gRPC في الإنتاج: contracts و DataLoader و limits و deadlines
- 110Kafka على أكتر من zone و region: الـ replication والـ ISR والـ acks والـ MirrorMaker والـ failover
- 111TypeScript و runtime boundaries: الـ types بتختفي، والـ schemas لأ
- 112ORM ولا SQL: query builders و repositories و migrations و transactions
- 113الـ Serverless من جُوّه: cold starts و freeze و timeouts و connections
- 114الـ Testing Pyramid: unit و integration و e2e على Postgres حقيقية
- 115Contract Testing و Property-Based Testing بـ fast-check
- 116الـ Payments: idempotency و webhooks و refunds و reconciliation
- 117الـ Timezones والـ Internationalization: UTC و DST والـ locales والـ plurals والفلوس
- 118الـ Privacy والـ Data Retention: consent و export و erasure و crypto shredding
- 119الـ ADRs والـ Feature Flags: القرارات المكتوبة والـ rollout من غير deploy
- 120Multi-region active-active: حل الـ conflicts بـ HLC و CRDTs
- 121Readiness و Liveness و Startup Probes: الـ pod جاهز ولا عايش؟
- 122Incident Runbooks: من الـ alert للـ postmortem