system-design-bangla

🚨 Production Outages (Root Cause Engineering Series)

🧠 Philosophy

āĻāχ āϏāĻŋāϰāĻŋāϜāϟāĻž āϞ⧇āĻ–āĻžāϰ āφāϏāϞ āωāĻĻā§āĻĻ⧇āĻļā§āϝ debugging shortcuts āĻļ⧇āĻ–āĻžāύ⧋ āύāĻžāĨ¤

āĻŦāϰāĻ‚ āφāĻŽāĻŋ āϚāĻžāχ āφāĻĒāύāĻžāϰāĻž āĻŦ⧁āĻā§āύ:

Systems āφāϏāϞ⧇ āϕ⧀āĻ­āĻžāĻŦ⧇ āϭ⧇āϙ⧇ āĻĒāĻĄāĻŧ⧇, āĻāĻŦāĻ‚ āϕ⧇āύ āϤāĻžāϰāĻž āĻ āĻŋāĻ• āĻ“āχ āύāĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āϟ āωāĻĒāĻžāϝāĻŧ⧇āχ āĻ­āĻžāĻ™āϤ⧇ āĻŦāĻžāĻ§ā§āϝ āĻšāϝāĻŧāĨ¤

āφāĻŽāĻžāϰ āĻāĻ•āϟāĻž āĻŦāĻŋāĻļā§āĻŦāĻžāϏ āφāϛ⧇ āĻāχ āύāĻŋāϝāĻŧ⧇:

āϕ⧋āύ⧋ system āĻšā§āϟ āĻ•āϰ⧇, random āĻ­āĻžāĻŦ⧇ fail āĻ•āϰ⧇ āύāĻžāĨ¤
āĻĒā§āϰāϤāĻŋāϟāĻž failure āφāϏāϞ⧇ āϏ⧇āχ system-āĻāϰ design-āĻāϰ āĻŽāĻ§ā§āϝ⧇āχ āϞ⧇āĻ–āĻž āĻĨāĻžāϕ⧇ — āĻļ⧁āϧ⧁ āφāĻŽāϰāĻž āϏ⧇āϟāĻž āφāϗ⧇ āĻĨ⧇āϕ⧇ āĻĻ⧇āĻ–āĻŋ āύāĻžāĨ¤

āϤāĻžāχ āĻāχ āϏāĻŋāϰāĻŋāĻœā§‡ āĻĒā§āϰāϤāĻŋāϟāĻž incident-āϕ⧇ āφāĻŽāĻŋ āĻĻ⧇āĻ–āĻŦ āĻāχ āĻĻ⧃āĻˇā§āϟāĻŋāϕ⧋āĻŖ āĻĨ⧇āϕ⧇:


📝 āĻāĻ•āϟāĻŋ āϛ⧋āĻŸā§āϟ āĻĄāĻŋāϏāĻ•ā§āϞ⧇āχāĻŽāĻžāϰ

āĻāχ āϏāĻŋāϰāĻŋāĻœā§‡āϰ āĻĒā§āϰāϤāĻŋāϟāĻŋ āϏāĻŋāύāĻžāϰāĻŋāĻ“ āϕ⧋āύ⧋ āĻ•āĻžāĻ˛ā§āĻĒāύāĻŋāĻ• āĻĨāĻŋāĻ“āϰāĻŋ āĻŦāĻž āĻŦāχ āĻĨ⧇āϕ⧇ āύ⧇āĻ“āϝāĻŧāĻž āύāϝāĻŧāĨ¤ āĻāϗ⧁āϞ⧋ āφāĻŽāĻžāϰ āύāĻŋāĻœā§‡āϰ āĻ•ā§āϝāĻžāϰāĻŋāϝāĻŧāĻžāϰ⧇ āĻĢ⧇āϏ āĻ•āϰāĻž āĻŦāĻžāĻ¸ā§āϤāĻŦ āĻĒā§āϰ⧋āĻĄāĻžāĻ•āĻļāύ āĻ•ā§āĻ°ā§āϝāĻžāĻļ, āϰāĻžāϤ⧇āϰ āĻĒāϰ āϰāĻžāϤ āϜāĻžāĻ—āĻž āĻ¸ā§āĻŸā§āϰāĻžāĻ—āϞ āĻāĻŦāĻ‚ āĻ…āύ-āĻĢāĻŋāĻ˛ā§āĻĄ root cause āĻ…ā§āϝāĻžāύāĻžāϞāĻŋāϏāĻŋāϏ⧇āϰ āĻ…āĻ­āĻŋāĻœā§āĻžāϤāĻž āĻĨ⧇āϕ⧇ āϞ⧇āĻ–āĻžāĨ¤


📌 āϏ⧂āϚāĻŋāĻĒāĻ¤ā§āϰ

đŸ—„ī¸ Database Scenarios

The Silent MySQL Crash

Field Detail
Time āϰāĻžāϤ ā§§ā§§:ā§Šā§¨
Symptom Dashboard load āĻšāĻšā§āϛ⧇ āύāĻž, API hang āĻ•āϰāϛ⧇
Root Cause Disk 100% full → MySQL-āĻāϰ write path āĻĒ⧁āϰ⧋āĻĒ⧁āϰāĻŋ āĻŦā§āϞāĻ•
Resolution Time āĻĒā§āϰāĻžāϝāĻŧ ā§§ā§Ģ āĻŽāĻŋāύāĻŋāϟ
Severity 🔴 Critical

📟 Alert

“Lahin bhai, system āĻ…āύ⧇āĻ• slowâ€Ļ userāϰāĻž dashboard load āĻ•āϰāϤ⧇ āĻĒāĻžāϰāϛ⧇ āύāĻžāĨ¤â€

āĻāχ āϧāϰāύ⧇āϰ message āĻĒ⧇āϞ⧇ āĻĒā§āϰāĻĨāĻŽ instinct āĻšāϝāĻŧ āĻ­āĻžāĻŦāĻž āϝ⧇ app āĻŦāĻž code-āĻ āϕ⧋āĻĨāĻžāĻ“ bug āφāϛ⧇āĨ¤ āĻ•āĻŋāĻ¨ā§āϤ⧁ āĻŦ⧇āĻļāĻŋāϰāĻ­āĻžāĻ— āϏāĻŽāϝāĻŧ āϏāĻŽāĻ¸ā§āϝāĻžāϟāĻž āĻ…āύ⧇āĻ• āύāĻŋāĻšā§‡āϰ layer-āĻ āĻŦāϏ⧇ āĻĨāĻžāϕ⧇āĨ¤


🔍 Investigation Timeline

ā§§ā§§:ā§Šā§Ģ PM — Application Layer-āĻ āĻĒā§āϰāĻĨāĻŽ āύāϜāϰ

pm2 logs

API process āϤ⧋ āĻŦ⧇āρāĻšā§‡ āφāϛ⧇āĨ¤ Workers-āĻ“ āϚāϞāϛ⧇āĨ¤ āϏāĻŦ āĻĻ⧇āϖ⧇ āĻŽāύ⧇ āĻšāĻšā§āϛ⧇ āĻ āĻŋāĻ•āχ āφāϛ⧇āĨ¤

āϤāĻžāϰāĻĒāϰ āĻšā§‡āĻ• āĻ•āϰāĻž āĻšāϞ⧋:

curl /api/dashboard

→ āĻ•āĻŋāϛ⧁āχ āĻĢ⧇āϰāϤ āφāϏāϛ⧇ āύāĻž, āĻļ⧁āϧ⧁ hang āĻ•āϰ⧇ āφāϛ⧇āĨ¤

āĻāϟāĻžāχ āφāϏāϞ⧇ āĻĒā§āϰāĻĨāĻŽ clue — process āĻœā§€āĻŦāĻŋāϤ, āĻ•āĻŋāĻ¨ā§āϤ⧁ āϕ⧋āύ⧋ request-āχ āĻāĻ—ā§‹āĻšā§āϛ⧇ āύāĻžāĨ¤ āĻŽāĻžāύ⧇ āϕ⧋āĻĨāĻžāĻ“ āĻāĻ•āϟāĻž āϜāĻŋāύāĻŋāϏ āφāϟāϕ⧇ āφāϛ⧇āĨ¤


ā§§ā§§:ā§Šā§Ž PM — āĻāĻŦāĻžāϰ Database-āĻāϰ āĻĻāĻŋāϕ⧇ āϤāĻžāĻ•āĻžāϞāĻžāĻŽ

systemctl status mysql

✔ MySQL “running” āĻĻ⧇āĻ–āĻžāĻšā§āϛ⧇ — āĻ•āĻŋāĻ¨ā§āϤ⧁ āĻāχ signal-āϟāĻž āφāϏāϞ⧇ āĻŦāĻŋāĻ­ā§āϰāĻžāĻ¨ā§āϤāĻŋāĻ•āϰāĨ¤

mysql -u root -p

→ āĻāϟāĻžāĻ“ āφāϟāϕ⧇ āϗ⧇āϞāĨ¤

āĻŽāĻžāύ⧇ DB āĻŸā§‡āĻ•āύāĻŋāĻ•ā§āϝāĻžāϞāĻŋ “up” āφāϛ⧇, āĻ•āĻŋāĻ¨ā§āϤ⧁ āĻ•āĻžāϜ āĻ•āϰāϛ⧇ āύāĻžāĨ¤ āĻĻ⧁āĻŸā§‹ āφāϞāĻžāĻĻāĻž āϜāĻŋāύāĻŋāϏāĨ¤


ā§§ā§§:ā§Ēā§Ļ PM — Infrastructure Layer, āĻāĻŦāĻ‚ āĻāĻ–āĻžāύ⧇āχ āωāĻ¤ā§āϤāϰ āĻĒāĻžāĻ“āϝāĻŧāĻž āϗ⧇āϞ

df -h

→ Disk 100% fullāĨ¤

āĻŦā§āϝāĻžāϏ, āĻāĻ–āĻžāύ⧇āχ āĻĒ⧁āϰ⧋ āĻ—āĻ˛ā§āĻĒ⧇āϰ āϰāĻšāĻ¸ā§āϝ āϖ⧁āϞ⧇ āϗ⧇āϞāĨ¤


🧠 System āϕ⧀ āĻšāϝāĻŧ⧇āĻ›āĻŋāϞ, āφāϏāϞ⧇

āĻāϟāĻž āϕ⧋āύ⧋ crash āύāĻžāĨ¤

āĻāϟāĻž āĻšāϞ⧋ backpressure āϝāĻžāϰ āϕ⧋āύ⧋ escape path āύ⧇āχ:

Request āφāϏ⧇
 → MySQL-āĻ write āĻ•āϰāϤ⧇ āϝāĻžāϝāĻŧ
 → Disk full, āϤāĻžāχ āĻŦā§āϞāĻ• āĻšāϝāĻŧ⧇ āϝāĻžāϝāĻŧ
 → Transaction āφāϟāϕ⧇ āĻĨāĻžāϕ⧇
 → Connection āĻ•āĻ–āύ⧋ release āĻšāϝāĻŧ āύāĻž
 → Pool āĻ­āϰ⧇ āϝāĻžāϝāĻŧ
 → āĻĒ⧁āϰ⧋ API layer āĻĨ⧇āĻŽā§‡ āϝāĻžāϝāĻŧ

System āφāϏāϞ⧇ fail āĻ•āϰāϛ⧇ āύāĻžāĨ¤ āϏ⧇ āĻļ⧁āϧ⧁ āϏ⧀āĻŽāĻžāύāĻžāϰ āϏāĻžāĻŽāύ⧇ āĻĻāĻžāρāĻĄāĻŧāĻŋāϝāĻŧ⧇ āĻ…āύāĻ¨ā§āϤāĻ•āĻžāϞ āĻ…āĻĒ⧇āĻ•ā§āώāĻž āĻ•āϰāϛ⧇āĨ¤


🔗 Root Cause Chain

Disk Full
→ Write path āĻŦā§āϞāĻ•
→ Transaction āĻļ⧇āώ āĻšāϤ⧇ āĻĒāĻžāϰāϛ⧇ āύāĻž
→ Connection āĻ–ā§‹āϞāĻž āĻĨ⧇āϕ⧇ āϝāĻžāĻšā§āϛ⧇
→ Connection pool saturate
→ āύāϤ⧁āύ āϕ⧋āύ⧋ request āĻāĻ—ā§‹āϤ⧇ āĻĒāĻžāϰāϛ⧇ āύāĻž
→ āϏāĻŋāĻ¸ā§āĻŸā§‡āĻŽ-āĻ“āϝāĻŧāĻžāχāĻĄ stall

đŸ› ī¸ āϝ⧇āĻ­āĻžāĻŦ⧇ āĻ āĻŋāĻ• āĻ•āϰāĻž āĻšāϞ⧋

du -sh /* | sort -rh | head -20

āĻŦāĻŋāĻļ⧇āώāĻ­āĻžāĻŦ⧇ āĻšā§‡āĻ• āĻ•āϰāĻžāϰ āϜāĻžāϝāĻŧāĻ—āĻž:

āϤāĻžāϰāĻĒāϰ:


🧠 āφāϏāϞ āĻļāĻŋāĻ•ā§āώāĻž

Flash Sale Crash: Pool āύāϝāĻŧ, āφāϏāϞ āĻ­āĻŋāϞ⧇āύ āĻ›āĻŋāϞ Query Latency

📟 Alert

“āϏ⧇āϞ āĻļ⧁āϰ⧁ āĻšāϤ⧇āχ āĻĒ⧁āϰ⧋ āĻ…ā§āϝāĻžāĻĒ āĻĄāĻžāωāύ!”

āĻĢā§āĻ˛ā§āϝāĻžāĻļ āϏ⧇āϞ⧇āϰ āĻĒā§āϰāĻĨāĻŽ āĻŽāĻŋāύāĻŋāĻŸā§‡āχ āĻāχ message — āφāϰ āĻāχ āϧāϰāύ⧇āϰ incident-āĻ āϏāĻŦāĻžāχ āĻĒā§āϰāĻĨāĻŽā§‡ server āĻŦāĻž āχāύāĻĢā§āϰāĻžāϕ⧇ āĻĻā§‹āώ āĻĻ⧇āϝāĻŧāĨ¤ āφāϏāϞ āĻ•āĻžāϰāĻŖ āĻ•āĻŋāĻ¨ā§āϤ⧁ āĻ…āĻ¨ā§āϝ āϜāĻžāϝāĻŧāĻ—āĻžāϝāĻŧ āĻ›āĻŋāϞāĨ¤


🔍 Investigation Timeline

ā§Ž:ā§Ļā§Ļ PM — Traffic Spike

100 users → 15,000 users

āĻšāĻ āĻžā§Ž āĻ•āϰ⧇āχ āĻāχ āϜāĻžāĻŽā§āĻĒāĨ¤ āϕ⧋āύ⧋ warm-up āύ⧇āχ, āϏāϰāĻžāϏāϰāĻŋ ā§§ā§Ģā§Ļx āĻŸā§āϰāĻžāĻĢāĻŋāĻ•āĨ¤


ā§Ž:ā§Ļā§Ģ PM — Application Layer-āĻ āϝāĻž āĻĻ⧇āĻ–āĻž āϗ⧇āϞ

pm2 logs

Error āϗ⧁āϞ⧋:

āĻĒā§āϰāĻĨāĻŽ āĻĻ⧇āĻ–āĻžāϝāĻŧ āĻŽāύ⧇ āĻšāϝāĻŧ “connection āĻļāĻ°ā§āĻŸā§‡āĻœâ€ — āĻ•āĻŋāĻ¨ā§āϤ⧁ āĻāχ āϧāĻžāϰāĻŖāĻžāϟāĻž āϭ⧁āϞ, āĻāĻŦāĻ‚ āĻāϟāĻžāχ āϏāĻŦāĻšā§‡āϝāĻŧ⧇ āĻ•āĻŽāύ trapāĨ¤


ā§Ž:ā§§ā§Ļ PM — Database Layer āϖ⧁āρāϟāĻŋāϝāĻŧ⧇ āĻĻ⧇āĻ–āϞāĻžāĻŽ

SHOW STATUS LIKE 'Threads_running';
Threads_running = 10 (maxed out)

āĻāϟāĻž MySQL-āĻāϰ āϕ⧋āύ⧋ hard limit āύāĻžāĨ¤ āĻāϟāĻž āφāϏāϞ⧇ application-āĻāϰ āύāĻŋāĻœā§‡āϰ connection pool saturate āĻšāϝāĻŧ⧇ āĻ—āĻŋāϝāĻŧ⧇āĻ›āĻŋāϞāĨ¤


🧠 āφāϏāϞ⧇ āϕ⧀ āϘāϟāĻ›āĻŋāϞ

āĻāχ āϏāĻŋāĻ¸ā§āĻŸā§‡āĻŽ connection-bound āύāĻžāĨ¤

āĻāϟāĻž time-boundāĨ¤

āĻāĻ•āϟāĻž slow query (~500ms)
→ Connection āĻĻā§€āĻ°ā§āϘ āϏāĻŽāϝāĻŧ āϧāϰ⧇ āϰāĻžāĻ–āĻž āĻšāϝāĻŧ
→ Pool āϝāĻĨ⧇āĻˇā§āϟ āϤāĻžāĻĄāĻŧāĻžāϤāĻžāĻĄāĻŧāĻŋ recycle āĻ•āϰāϤ⧇ āĻĒāĻžāϰāϛ⧇ āύāĻž
→ Queue āϜāĻŽāϤ⧇ āĻļ⧁āϰ⧁ āĻ•āϰ⧇
→ Latency āφāϰāĻ“ āĻŦāĻžāĻĄāĻŧ⧇
→ āĻāĻŦāĻ‚ āĻāϟāĻž āĻāĻ•āϟāĻž positive feedback loop-āĻ āĻĒāϰāĻŋāĻŖāϤ āĻšāϝāĻŧ

āĻŽāĻžāύ⧇ āϏāĻŽāĻ¸ā§āϝāĻžāϟāĻž āύāĻŋāĻœā§‡āχ āύāĻŋāĻœā§‡āϕ⧇ āφāϰāĻ“ āĻ–āĻžāϰāĻžāĻĒ āĻ•āϰāĻ›āĻŋāϞāĨ¤


🔗 Root Cause Chain

Missing Index
→ Full table scan
→ Query latency ~500ms
→ DB connection āĻĻā§€āĻ°ā§āϘāϏāĻŽāϝāĻŧ āϧāϰ⧇ āĻĨāĻžāĻ•āϛ⧇
→ Connection pool saturate (10 threads)
→ Request āϜāĻŽāĻž āĻšāĻšā§āϛ⧇
→ ETIMEDOUT + ER_CON_COUNT_ERROR
→ āĻĒ⧁āϰ⧋ āϏāĻŋāĻ¸ā§āĻŸā§‡āĻŽ āĻ•āϞāĻžāĻĒā§āϏ

🧮 āφāϏāϞ āĻšāĻŋāϏāĻžāĻŦ (Little’s Law āĻŦāĻžāĻ¸ā§āϤāĻŦ⧇ āϕ⧀āĻ­āĻžāĻŦ⧇ āĻ•āĻžāϜ āĻ•āϰ⧇)

Fix-āĻāϰ āφāϗ⧇

10 threads / 0.5s = 20 QPS

āĻŽāĻžāύ⧇ āϏāĻ°ā§āĻŦā§‹āĻšā§āϚ ⧍ā§ĻāϟāĻž request āĻĒā§āϰāϤāĻŋ āϏ⧇āϕ⧇āĻ¨ā§āĻĄā§‡ āĻšā§āϝāĻžāĻ¨ā§āĻĄā§‡āϞ āĻ•āϰāĻžāϰ āĻ•ā§āώāĻŽāϤāĻž āĻ›āĻŋāϞ — āφāϰ āĻŸā§āϰāĻžāĻĢāĻŋāĻ• āĻ›āĻŋāϞ āĻšāĻžāϜāĻžāϰ⧇ āĻšāĻžāϜāĻžāϰāĨ¤

Fix-āĻāϰ āĻĒāϰ⧇

10 threads / 0.01s = 1000 QPS

āĻāĻ•āχ ā§§ā§ĻāϟāĻž thread, āĻ•āĻŋāĻ¨ā§āϤ⧁ āĻāĻ–āύ ā§Ģā§Ļ āϗ⧁āĻŖ āĻŦ⧇āĻļāĻŋ throughputāĨ¤ Thread āĻŦāĻžāĻĄāĻŧāĻžāχāύāĻŋ, āĻļ⧁āϧ⧁ latency āĻ•āĻŽāĻŋāϝāĻŧ⧇āĻ›āĻŋāĨ¤


đŸ› ī¸ āϝ⧇āĻ­āĻžāĻŦ⧇ āĻ āĻŋāĻ• āĻ•āϰāĻž āĻšāϞ⧋

SHOW FULL PROCESSLIST;
CREATE INDEX idx_user_id;

āĻĢāϞāĻžāĻĢāϞ:


🧠 āφāϏāϞ āĻļāĻŋāĻ•ā§āώāĻž

Migration Disaster: The Table that Froze Production

🧱 Environment

āύ⧋āϟ: āĻāχ āϘāϟāύāĻžāϟāĻŋ MySQL 5.x-āĻ āϘāĻŸā§‡āĻ›āĻŋāϞ, āϝ⧇āĻ–āĻžāύ⧇ ALTER TABLE ... ADD COLUMN-āĻāϰ āĻŽāϤ⧋ āĻ…āύ⧇āĻ• DDL āĻ…āĻĒāĻžāϰ⧇āĻļāύ āĻŸā§‡āĻŦāĻŋāϞ āϰāĻŋāĻŦāĻŋāĻ˛ā§āĻĄ āϘāϟāĻžāϤ⧇ āĻĒāĻžāϰāϤ āĻāĻŦāĻ‚ āωāĻ˛ā§āϞ⧇āĻ–āϝ⧋āĻ—ā§āϝ āϏāĻŽāϝāĻŧ āϧāϰ⧇ āĻŽā§‡āϟāĻžāĻĄā§‡āϟāĻž āϞāĻ• āϧāϰ⧇ āϰāĻžāĻ–āϤ⧇ āĻĒāĻžāϰāϤāĨ¤ āφāϧ⧁āύāĻŋāĻ• MySQL 8 āĻ­āĻžāĻ°ā§āϏāύāϗ⧁āϞ⧋ āĻāχ āϧāϰāύ⧇āϰ āĻ…āύ⧇āĻ• āĻ…āĻĒāĻžāϰ⧇āĻļāύ⧇āϰ āϜāĻ¨ā§āϝ ALGORITHM=INSTANT āϏāĻžāĻĒā§‹āĻ°ā§āϟ āĻ•āϰ⧇, āϝāĻžāϰ āĻĢāϞ⧇ āĻāχ āύāĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āϟ āϧāϰāύ⧇āϰ āĻŦā§āϝāĻ°ā§āĻĨāϤāĻž āĻāĻ–āύ āĻ…āύ⧇āĻ• āĻ•āĻŽ āĻĻ⧇āĻ–āĻž āϝāĻžāϝāĻŧāĨ¤

📌 Incident Summary

Field Detail
Time āĻĻ⧁āĻĒ⧁āϰ ⧍:ā§§ā§Ģ
Symptom API suddenly hanging, database CPU low, connections increasing
Root Cause A seemingly harmless migration acquired metadata locks and blocked the write path
Resolution Kill migration session
Severity 🔴 Critical

📟 Alert

“āĻ­āĻžāχ API āϖ⧁āĻŦ slow.”

āĻ•āϝāĻŧ⧇āĻ• āĻŽāĻŋāύāĻŋāϟ āĻĒāϰ⧇:

“Create user āĻ•āĻžāϜ āĻ•āϰāϛ⧇ āύāĻžāĨ¤â€

āϤāĻžāϰāĻĒāϰ:

“Checkout āĻ•āĻžāϜ āĻ•āϰāϛ⧇ āύāĻžāĨ¤â€

āϏāĻŦāĻšā§‡āϝāĻŧ⧇ āĻ…āĻĻā§āϭ⧁āϤ āĻŦāĻŋāώāϝāĻŧ āĻ›āĻŋāϞ:

āĻ•āĻŋāĻ¨ā§āϤ⧁ āĻĒ⧁āϰ⧋ system āĻ•āĻžāĻ°ā§āϝāϤ unusableāĨ¤

🔍 Investigation Timeline

2:17 PM

SHOW PROCESSLIST;

āĻĻ⧇āĻ–āĻž āϗ⧇āϞ⧋:

Waiting for table metadata lock
Waiting for table metadata lock
Waiting for table metadata lock
Waiting for table metadata lock

2:19 PM

Deploy pipeline-āĻāϰ āĻ…āĻ‚āĻļ āĻšāĻŋāϏ⧇āĻŦ⧇ āĻāĻ•āϟāĻŋ migration run āĻšāϝāĻŧ⧇āĻ›āĻŋāϞ:

ALTER TABLE users
ADD COLUMN last_login_ip VARCHAR(45);

āĻĻ⧇āĻ–āϤ⧇ harmlessāĨ¤

āĻ•āĻŋāĻ¨ā§āϤ⧁ users table-āĻ āĻ›āĻŋāϞ:

43 million rows

🧠 System āϕ⧀ āĻšāϝāĻŧ⧇āĻ›āĻŋāϞ, āφāϏāϞ⧇

MySQL 5.x schema change āĻ•āϰāĻžāϰ āφāϗ⧇ table-āĻāϰ āωāĻĒāϰ metadata lock āύ⧇āϝāĻŧ āĻāĻŦāĻ‚ āĻ…āύ⧇āĻ• DDL operation-āĻāϰ āĻ•ā§āώ⧇āĻ¤ā§āϰ⧇ table rebuild āĻ•āϰ⧇āĨ¤

āĻŽāĻžāχāĻ—ā§āϰ⧇āĻļāύ āĻļ⧁āϰ⧁ āĻšāϞ⧋
→ āĻŽā§‡āϟāĻžāĻĄā§‡āϟāĻž āϞāĻ• āύ⧇āĻ“āϝāĻŧāĻž āĻšāϞ⧋
→ āύāϤ⧁āύ write āĻ…āĻĒ⧇āĻ•ā§āώāĻžāϝāĻŧ āĻĨāĻžāĻ•āϞ
→ āĻŸā§āϰāĻžāύāĻœā§āϝāĻžāĻ•āĻļāύ āϜāĻŽāĻž āĻšāϤ⧇ āϞāĻžāĻ—āϞ
→ āĻ•āĻžāύ⧇āĻ•āĻļāύ āĻĒ⧁āϞ āĻ­āϰ⧇ āϗ⧇āϞ
→ API āφāϟāϕ⧇ āϝ⧇āϤ⧇ āĻļ⧁āϰ⧁ āĻ•āϰāϞ
→ āϰāĻŋāĻŸā§āϰāĻžāχ āĻŦāĻžāĻĄāĻŧāϤ⧇ āϞāĻžāĻ—āϞ
→ āĻĒ⧁āϰ⧋ āϏāĻŋāĻ¸ā§āĻŸā§‡āĻŽ āĻĨāĻŽāϕ⧇ āϗ⧇āϞ

🔗 Root Cause Chain

ALTER TABLE āĻļ⧁āϰ⧁ āĻšāϞ⧋
→ āĻŽā§‡āϟāĻžāĻĄā§‡āϟāĻž āϞāĻ• āύ⧇āĻ“āϝāĻŧāĻž āĻšāϞ⧋
→ INSERT/UPDATE āĻŦā§āϞāĻ• āĻšāϝāĻŧ⧇ āϗ⧇āϞ
→ āĻŸā§āϰāĻžāύāĻœā§āϝāĻžāĻ•āĻļāύāϗ⧁āϞ⧋ āĻ–ā§‹āϞāĻž āĻĨ⧇āϕ⧇ āϗ⧇āϞ
→ āĻ•āĻžāύ⧇āĻ•āĻļāύ āϰāĻŋāϞāĻŋāϜ āĻšāϞ⧋ āύāĻž
→ āĻĒ⧁āϞ saturation āĻĻ⧇āĻ–āĻž āĻĻāĻŋāϞ
→ āϰāĻŋāϕ⧋āϝāĻŧ⧇āĻ¸ā§āϟ queue āĻŦāĻžāĻĄāĻŧāϤ⧇ āĻĨāĻžāĻ•āϞ
→ āϏāĻ°ā§āĻŦāĻ¤ā§āϰ āϟāĻžāχāĻŽāφāωāϟ

đŸ› ī¸ Resolution

SHOW PROCESSLIST;

Output

Id    User   Command   Time    State
101   deploy Query     420     altering table
102   app    Query     300     Waiting for table metadata lock
103   app    Query     280     Waiting for table metadata lock
104   app    Query     275     Waiting for table metadata lock

āĻāĻ–āĻžāύ⧇:

āϤāĻ–āύ:

KILL 101;

āĻĻāĻŋāϞ⧇:

đŸ›Ąī¸ Prevention

🧠 āφāϏāϞ āĻļāĻŋāĻ•ā§āώāĻž

> āĻŦ⧇āĻļāĻŋāϰāĻ­āĻžāĻ— āĻĒā§āϰ⧋āĻĄāĻžāĻ•āĻļāύ āφāωāĻŸā§‡āϜ āϏāĻŋāĻ¸ā§āĻŸā§‡āĻŽ āϭ⧇āϙ⧇ āĻĢ⧇āϞāĻžāϰ āĻ•āĻžāϰāϪ⧇ āĻšāϝāĻŧ āύāĻžāĨ¤

> āĻāϗ⧁āϞ⧋ āĻšāϝāĻŧ āϤāĻ–āύ, āϝāĻ–āύ āϏāĻŋāĻ¸ā§āĻŸā§‡āĻŽāϕ⧇ āĻŸā§āϰāĻžāĻĢāĻŋāĻ• āϏāĻžāĻ°ā§āĻ­ āĻ•āϰāĻž āĻ…āĻŦāĻ¸ā§āĻĨāĻžāϤ⧇āχ āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ āĻ•āϰāϤ⧇ āĻŦāϞāĻž āĻšāϝāĻŧāĨ¤

âš™ī¸ Application & Process Management Scenarios

The 255-Character Crash Loop

🧠 Philosophy

āĻāϟāĻž āϕ⧋āύ⧋ bug fixing āĻ—āĻ˛ā§āĻĒ āύāĻžāĨ¤

āĻāϟāĻž āĻšāϞ⧋ āĻāĻŽāύ āĻāĻ•āϟāĻž āϘāϟāύāĻž āϝ⧇āĻ–āĻžāύ⧇ āϧāϰāĻž āĻšā§Ÿā§‡āĻ›āĻŋāϞ:

“Database error āĻŽāĻžāύ⧇āχ application handle āĻ•āϰ⧇ āĻĢ⧇āϞāĻŦā§‡â€

āĻ•āĻŋāĻ¨ā§āϤ⧁ production āϏ⧇āχ āϧāĻžāϰāĻŖāĻž follow āĻ•āϰ⧇ āύāĻžāĨ¤

Production āĻļ⧁āϧ⧁ āϏ⧇āϟāĻžāχ āϚāĻžāϞāĻžāϝāĻŧ āϝ⧇āϟāĻž āĻŦāĻžāĻ¸ā§āϤāĻŦ⧇ implement āĻ•āϰāĻž āĻšāϝāĻŧ⧇āϛ⧇āĨ¤


📌 Incident Summary

Field Detail
Time āϰāĻžāϤ (approx)
Symptom API flapping — restart loop, dashboard/API intermittently unreachable
Root Cause Service layer-āĻ uncaught DB error → process crash → PM2 restart loop
Resolution pm2 restart āĻĻāĻŋāϝāĻŧ⧇ stabilize, āĻĒāϰ⧇ code-level fix
Severity 🔴 Critical

🧱 System Context

Stack:

Layered Architecture

Controller Layer  →  try/catch āĻ›āĻŋāϞ
Service Layer     →  try/catch āĻ›āĻŋāϞ āύāĻž

Endpoint

POST /users

Database Schema

CREATE TABLE users (
  id INT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(50)
);

Design Assumption


đŸ’Ĩ Incident Trigger

āĻāĻ•āϜāύ user āĻĒāĻžāĻ āĻžāϝāĻŧ:

name = "A very long string exceeding 50 characters........"

MySQL āĻ āĻŋāĻ•āĻ­āĻžāĻŦ⧇ reject āĻ•āϰ⧇:

ER_DATA_TOO_LONG: Data too long for column 'name'

(āĻāχ error code-āĻāϰ āĻŽāĻžāύ⧇ āĻšāϞ⧋ — column-āĻ āϝāϤāϟ⧁āϕ⧁ capacity āφāϛ⧇, āϤāĻžāϰ āĻšā§‡āϝāĻŧ⧇ āĻŦ⧇āĻļāĻŋ data āĻĒāĻžāĻ āĻžāύ⧋ āĻšāϝāĻŧ⧇āϛ⧇āĨ¤ MySQL āύāĻŋāĻœā§‡āχ āĻ•āĻŋāϛ⧁ āĻ­āĻžāϙ⧇āύāĻŋ, āϏ⧇ āĻļ⧁āϧ⧁ constraint enforce āĻ•āϰ⧇āϛ⧇āĨ¤)

āĻāϟāĻž expected behavior āĻ›āĻŋāϞāĨ¤

āĻ•āĻŋāĻ¨ā§āϤ⧁ āϏāĻŽāĻ¸ā§āϝāĻž āĻāĻ–āĻžāύ⧇ āĻļ⧁āϰ⧁ āĻšāϝāĻŧāĨ¤


🔍 Investigation Timeline

Step 1 — Application Layer

pm2 list
┌────â”Ŧ──────────â”Ŧ─────────â”Ŧ────────â”Ŧ─────────â”Ŧ──────────┐
│ id │ name     │ status  │ â†ē      │ uptime   │ cpu      │
├────â”ŧ──────────â”ŧ─────────â”ŧ────────â”ŧ─────────â”ŧ──────────┤
│ 0  │ api      │ online  │ 47     │ 3s       │ 0%       │
└────┴──────────┴─────────┴────────┴─────────┴──────────┘

👉 â†ē (restart count) āĻ…āύ⧇āĻ• āĻŦ⧇āĻļāĻŋ, uptime āĻŦāĻžāϰāĻŦāĻžāϰ āϰāĻŋāϏ⧇āϟ āĻšāĻšā§āϛ⧇ — process āĻ¸ā§āĻĨāĻŋāϤāĻŋāĻļā§€āϞ āĻšāĻšā§āϛ⧇ āύāĻž, repeatedly crash āĻ•āϰāϛ⧇āĨ¤

Step 2 — Crash Evidence

pm2 logs api --lines 100
ER_DATA_TOO_LONG: Data too long for column 'name'
[PM2] App [api] exited with code 1
[PM2] App [api] starting in -fork mode-
[PM2] App [api] online
ER_DATA_TOO_LONG: Data too long for column 'name'
[PM2] App [api] exited with code 1
[PM2] App [api] starting in -fork mode-
[PM2] App [api] online
ER_DATA_TOO_LONG: Data too long for column 'name'
[PM2] App [api] exited with code 1

👉 āĻāĻ•āχ error āĻŦāĻžāϰāĻŦāĻžāϰ āĻĢāĻŋāϰ⧇ āφāϏāϛ⧇ — pattern repeat āĻ•āϰāϛ⧇, random crash āύāĻžāĨ¤

Step 3 — āϕ⧋āĻĨāĻžāϝāĻŧ Error Catch āĻšāĻšā§āĻ›āĻŋāϞ āύāĻž

Controller layer-āĻ try/catch āĻ›āĻŋāϞ:

// controller.js
async function createUser(req, res) {
  try {
    const user = await userService.create(req.body.name);
    return res.status(201).json(user);
  } catch (err) {
    return res.status(500).json({ error: "Something went wrong" });
  }
}

āĻ•āĻŋāĻ¨ā§āϤ⧁ service layer-āĻ āϕ⧋āύ⧋ try/catch āĻ›āĻŋāϞ āύāĻž:

// userService.js
async function create(name) {
  // No try/catch here — query error throws straight up
  const result = await db.query(
    `INSERT INTO users (name) VALUES (?)`,
    [name]
  );
  return result;
}

āĻĻ⧇āĻ–āϤ⧇ āĻŽāύ⧇ āĻšāϝāĻŧ controller-āĻāϰ try/catch āĻĒ⧁āϰ⧋ request lifecycle āϕ⧇ cover āĻ•āϰāĻŦ⧇ — service layer āϝ⧇āĻ–āĻžāύ⧇āχ error throw āĻ•āϰ⧁āĻ•, āϏ⧇āϟāĻž await chain āϧāϰ⧇ controller-āĻāϰ catch āĻĒāĻ°ā§āϝāĻ¨ā§āϤ bubble up āĻ•āϰāĻž āωāϚāĻŋāϤāĨ¤

āĻ•āĻŋāĻ¨ā§āϤ⧁ practically, āĻāĻ–āĻžāύ⧇ error escape āĻ•āϰ⧇āĻ›āĻŋāϞ — āĻ•āĻžāϰāĻŖ error properly await āĻ•āϰāĻž āĻšāϝāĻŧāύāĻŋ āϕ⧋āύ⧋ āĻāĻ•āϟāĻž āϜāĻžāϝāĻŧāĻ—āĻžāϝāĻŧ (āĻāĻ•āϟāĻž fire-and-forget call, āĻŦāĻž āĻāĻ•āϟāĻž non-awaited promise āĻāϰ āϭ⧇āϤāϰ⧇ error āĻĨā§āϰ⧋ āĻšāϝāĻŧ⧇āĻ›āĻŋāϞ), āϝāĻžāϰ āĻĢāϞ⧇ āϏ⧇āϟāĻž controller-āĻāϰ synchronous catch boundary-āϰ āĻŦāĻžāχāϰ⧇ āĻ—āĻŋāϝāĻŧ⧇ unhandled rejection āĻšāĻŋāϏ⧇āĻŦ⧇ process-āϕ⧇ crash āĻ•āϰāĻŋāϝāĻŧ⧇āϛ⧇āĨ¤

👉 Lesson: “āĻāĻ•āϟāĻž try/catch āĻĨāĻžāĻ•āϞ⧇āχ āϝāĻĨ⧇āĻˇā§āĻŸâ€ āĻāχ āϧāĻžāϰāĻŖāĻžāϟāĻžāχ āϭ⧁āϞ āĻ›āĻŋāϞāĨ¤ Error āϝ⧇āĻ–āĻžāύ⧇ actually throw āĻšāϝāĻŧ, catch āϏ⧇āĻ–āĻžāύ⧇āχ āĻĨāĻžāĻ•āϤ⧇ āĻšāϝāĻŧ — āωāĻĒāϰ⧇āϰ layer-āĻāϰ catch āύāĻŋāĻšā§‡āϰ layer-āĻāϰ āĻĒā§āϰāϤāĻŋāϟāĻž throw path āϕ⧇ guarantee āĻ•āϰ⧇ āύāĻž, āĻŦāĻŋāĻļ⧇āώ āĻ•āϰ⧇ async/promise chain āĻ āĻŋāĻ•āĻ­āĻžāĻŦ⧇ āύāĻž āĻĨāĻžāĻ•āϞ⧇āĨ¤


❌ What Actually Happened

āĻĢāϞāĻžāĻĢāϞ:

👉 āĻāĻŦāĻ‚ process terminate āĻšāϝāĻŧ⧇ āϝāĻžāϝāĻŧ, PM2 restart āĻ•āϰ⧇, āĻ•āĻŋāĻ¨ā§āϤ⧁ āĻĒāϰ⧇āϰ request āφāϏāϞ⧇ āφāĻŦāĻžāϰ āĻāĻ•āχ āϜāĻžāϝāĻŧāĻ—āĻžāϝāĻŧ crash āĻ•āϰ⧇āĨ¤


🔁 PM2 Restart Loop

Service layer-āĻ error throw
      ↓
Controller-āĻāϰ catch escape āĻ•āϰ⧇
      ↓
Node process crash (unhandled rejection)
      ↓
PM2 detects crash → restart
      ↓
āĻĒāϰ⧇āϰ identical request āĻ āφāĻŦāĻžāϰ same crash
      ↓
Restart count āĻŦāĻžāĻĄāĻŧāϤ⧇ āĻĨāĻžāϕ⧇ (47+)

System unstable, from outside āĻĻ⧇āĻ–āϤ⧇ āĻŽāύ⧇ āĻšāĻšā§āĻ›āĻŋāϞ:

“API randomly down / flapping”


✅ Resolution

pm2 restart api

👉 āĻāχ āĻ•āĻŽāĻžāĻ¨ā§āĻĄ āϚāĻžāϞāĻžāύ⧋āϰ āĻĒāϰ system stable āĻšāϝāĻŧ⧇ āĻ—āĻŋāϝāĻŧ⧇āĻ›āĻŋāϞ — loop āĻĨ⧇āĻŽā§‡ āĻ—āĻŋāϝāĻŧ⧇āĻ›āĻŋāϞāĨ¤

āĻāϟāĻž āĻāĻ•āϟāĻž āϗ⧁āϰ⧁āĻ¤ā§āĻŦāĻĒā§‚āĻ°ā§āĻŖ āĻĒāϝāĻŧ⧇āĻ¨ā§āϟ: āĻāχ incident āĻāĻ•āϟāĻž self-sustaining infinite loop āĻ›āĻŋāϞ āύāĻžāĨ¤ āĻāϟāĻž āĻ›āĻŋāϞ āĻāĻ•āχ bad input āĻŦāĻžāϰāĻŦāĻžāϰ āφāϏāĻžāϰ āĻĢāϞ⧇ āϤ⧈āϰāĻŋ āĻšāĻ“āϝāĻŧāĻž āĻāĻ•āϟāĻž crash burst — manual restart āĻĻ⧇āĻ“āϝāĻŧāĻžāϰ āϏāĻŽāϝāĻŧ āĻĨ⧇āϕ⧇ āύāϤ⧁āύ āϕ⧋āύ⧋ invalid request āύāĻž āφāϏāĻžāϝāĻŧ system āϏ⧁āĻ¸ā§āĻĨ āĻ…āĻŦāĻ¸ā§āĻĨāĻžāϝāĻŧ āĻĨ⧇āϕ⧇ āĻ—āĻŋāϝāĻŧ⧇āĻ›āĻŋāϞāĨ¤ Restart āύāĻŋāĻœā§‡ āĻ—āĻŋāϝāĻŧ⧇ underlying bug āϕ⧇ fix āĻ•āϰ⧇āύāĻŋ — āĻļ⧁āϧ⧁ āϏāĻžāĻŽāϝāĻŧāĻŋāĻ•āĻ­āĻžāĻŦ⧇ crash chain āϟāĻž āϭ⧇āϙ⧇ āĻĻāĻŋāϝāĻŧ⧇āĻ›āĻŋāϞāĨ¤ āϏ⧇āχ bad input āφāĻŦāĻžāϰ āφāϏāϞ⧇ crash āφāĻŦāĻžāϰ āĻšāϤ⧋, āϝāϤāĻ•ā§āώāĻŖ āύāĻž code-level fix āĻĻ⧇āĻ“āϝāĻŧāĻž āĻšāϝāĻŧāĨ¤


🧨 Root Cause

MySQL āĻāĻ–āĻžāύ⧇ āϕ⧋āύ⧋ āϏāĻŽāĻ¸ā§āϝāĻž āĻ•āϰ⧇āύāĻŋ — āϏ⧇ āĻļ⧁āϧ⧁ āĻŦāϞ⧇āϛ⧇ data column capacity exceed āĻ•āϰāϛ⧇āĨ¤

Real issue āĻ›āĻŋāϞ architectural:

Controller layer-āĻāϰ error handling-āϕ⧇ “āĻĒ⧁āϰ⧋ request lifecycle-āĻāϰ safety net” āĻ­āĻžāĻŦāĻž āĻšāϝāĻŧ⧇āĻ›āĻŋāϞ, āĻ•āĻŋāĻ¨ā§āϤ⧁ service layer-āĻāϰ āϭ⧇āϤāϰ⧇āϰ āĻāĻ•āϟāĻž uncaught throw path āϏ⧇āχ boundary-āϕ⧇ bypass āĻ•āϰ⧇ āĻ—āĻŋāϝāĻŧ⧇āĻ›āĻŋāϞāĨ¤


đŸ”Ĩ Why This Became an Outage

āϤāĻŋāύāϟāĻž component individually āϤāĻžāĻĻ⧇āϰ āύāĻŋāĻœā§‡āϰ āϜāĻžāϝāĻŧāĻ—āĻžāϝāĻŧ āĻ āĻŋāĻ• āĻ•āĻžāϜ āĻ•āϰ⧇āϛ⧇:

1. MySQL

✔ Correct constraint enforcement

2. Controller Layer

✔ try/catch āĻ›āĻŋāϞ, āĻ•āĻŋāĻ¨ā§āϤ⧁ āϏ⧇āϟāĻžāϰ coverage āĻ›āĻŋāϞ incomplete — āϏāĻŦ throw path cover āĻ•āϰ⧇āύāĻŋ

3. Service Layer

❌ āϕ⧋āύ⧋ try/catch āĻ›āĻŋāϞ āύāĻž — error āϏāϰāĻžāϏāϰāĻŋ uncaught āĻĨ⧇āϕ⧇ process crash āĻ•āϰāĻŋāϝāĻŧ⧇āϛ⧇

4. PM2

✔ Crash detect āĻ•āϰ⧇ restart āĻ•āϰ⧇āϛ⧇ (expected behavior) — āĻ•āĻŋāĻ¨ā§āϤ⧁ pm2 restart manual intervention-āχ āφāϏāϞ⧇ loop āĻĨāĻžāĻŽāĻŋāϝāĻŧ⧇āϛ⧇, PM2-āϰ auto-restart āύāĻŋāĻœā§‡ āĻĨ⧇āϕ⧇ āĻ•āĻŋāϛ⧁ “āĻ āĻŋāĻ•â€ āĻ•āϰ⧇āύāĻŋ


âš ī¸ Hidden Failure Mode

āĻāĻ•āϟāĻž upper-layer try/catch āĻĨāĻžāĻ•āĻž āĻŽāĻžāύ⧇āχ “error handled” — āĻāχ assumption āϟāĻžāχ false security āĻĻāĻŋāϝāĻŧ⧇āĻ›āĻŋāϞāĨ¤

Single bad request āĻāĻ•āϟāĻž crash trigger āĻ•āϰāϞ⧋ → PM2 restart āĻ•āϰāϞ⧋ → āφāĻŦāĻžāϰ same/similar bad request āĻāϞ⧇ āφāĻŦāĻžāϰ crash → āĻāχ pattern āϰāĻŋāĻĒāĻŋāϟ āĻšāϝāĻŧ⧇ restart count āĻŦāĻžāĻĄāĻŧāϤ⧇ āĻĨāĻžāĻ•āϞ⧋ — āϝāϤāĻ•ā§āώāĻŖ manual restart āύāĻž āĻĻ⧇āĻ“āϝāĻŧāĻž āĻšāϞ⧋ āĻāĻŦāĻ‚ traffic pattern āĻŦāĻĻāϞāĻžāϞ⧋āĨ¤


🧠 System Design Lesson

āϭ⧁āϞ āϧāĻžāϰāĻŖāĻž āĻ›āĻŋāϞ:

“Controller-āĻ try/catch āφāϛ⧇, āϤāĻžāχ āĻĒ⧁āϰ⧋ request safeāĨ¤â€

Reality:

āĻĒā§āϰāϤāĻŋāϟāĻž layer-āĻāϰ own error boundary āĻĒā§āϰāϝāĻŧā§‹āϜāύāĨ¤ Upper layer-āĻāϰ catch āύāĻŋāĻšā§‡āϰ layer-āĻāϰ āĻĒā§āϰāϤāĻŋāϟāĻž throw/reject path āϕ⧇ automatically cover āĻ•āϰ⧇ āύāĻž — āĻŦāĻŋāĻļ⧇āώ āĻ•āϰ⧇ async code-āĻ, āϝ⧇āĻ–āĻžāύ⧇ āĻāĻ•āϟāĻž missed await āĻŦāĻž un-awaited promise āϏāĻšāĻœā§‡āχ catch boundary āĻŦāĻžāχāĻĒāĻžāϏ āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇āĨ¤


đŸ› ī¸ Fix Applied

1. Service Layer-āĻ Proper Error Handling

// userService.js
async function create(name) {
  try {
    return await db.query(
      `INSERT INTO users (name) VALUES (?)`,
      [name]
    );
  } catch (err) {
    if (err.code === "ER_DATA_TOO_LONG") {
      const validationError = new Error("Input too long");
      validationError.statusCode = 400;
      throw validationError;
    }
    throw err;
  }
}

👉 āĻĒā§āϰāϤāĻŋāϟāĻž layer āύāĻŋāĻœā§‡āϰ errors āύāĻŋāĻœā§‡ handle āĻ•āϰ⧇ āĻāĻŦāĻ‚ proper, predictable error shape upward pass āĻ•āϰ⧇ — controller-āĻāϰ catch āϤāĻ–āύ āĻāĻ•āϟāĻž known shape-āĻāϰ āωāĻĒāϰ āĻ•āĻžāϜ āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇āĨ¤

2. Input Validation Before DB

if (name.length > 50) {
  return res.status(400).json({
    error: "Name exceeds maximum allowed length"
  });
}

3. PM2 Configuration Hardening

// ecosystem.config.js
module.exports = {
  apps: [{
    name: "api",
    script: "./server.js",
    max_restarts: 15,              // hard ceiling instead of unlimited
    min_uptime: "10s",             // crash within 10s doesn't count as a "successful" run
    exp_backoff_restart_delay: 100 // exponential backoff between restarts
  }]
};

👉 āĻāχ configuration āĻĨāĻžāĻ•āϞ⧇ repeated crash-āĻāϰ āĻ•ā§āώ⧇āĻ¤ā§āϰ⧇ PM2 āύāĻŋāĻœā§‡āχ restart āĻŦāĻ¨ā§āϧ āĻ•āϰ⧇ process-āϕ⧇ errored state-āĻ āϰāĻžāĻ–āϤ⧋ — manual intervention āĻāϰ āϜāĻ¨ā§āϝ āĻ…āĻĒ⧇āĻ•ā§āώāĻž āύāĻž āĻ•āϰāĻŋāϝāĻŧ⧇ āĻāĻ•āϟāĻž clean, alertable failure āϤ⧈āϰāĻŋ āĻšāϤ⧋āĨ¤

4. process.exit() āĻŦā§āϝāĻŦāĻšāĻžāϰ⧇āϰ āύ⧀āϤāĻŋ

process.exit() āĻļ⧁āϧ⧁ āĻāχ āĻ•ā§āώ⧇āĻ¤ā§āϰ⧇ use āĻ•āϰāĻž āωāϚāĻŋāϤ:

❌ āĻ•āĻ–āύ⧋āχ user input errors-āĻāϰ āϜāĻ¨ā§āϝ āύāϝāĻŧ — āĻāĻŦāĻ‚ āĻāχ incident-āĻ āϕ⧋āύ⧋ explicit process.exit() call āĻ›āĻŋāϞāĻ“ āύāĻž; crash āĻšāϝāĻŧ⧇āĻ›āĻŋāϞ Node-āĻāϰ default unhandled-rejection behavior āĻĨ⧇āϕ⧇āĨ¤


🧠 āφāϏāϞ āĻļāĻŋāĻ•ā§āώāĻž

Systems don’t fail randomly — they fail exactly according to their design boundaries.

āĻāχ case āĻ boundary āϟāĻž āĻ›āĻŋāϞ layer-āĻ­āĻŋāĻ¤ā§āϤāĻŋāĻ•, error-path āĻ­āĻŋāĻ¤ā§āϤāĻŋāĻ• āύāĻž:

Cron āϭ⧁āϞ āϟāĻžāχāĻŽāĻœā§‹āύ⧇ āĻŸā§āϰāĻŋāĻ—āĻžāϰ āĻšāĻ“āϝāĻŧāĻž

📟 Alert

āĻĒā§āϰāϤāĻŋāĻĻāĻŋāύ āϰāĻžāϤ ⧧⧍āϟāĻžāϝāĻŧ (Asia/Dhaka, UTC+6) āĻāĻ•āϟāĻž āĻĄā§‡āχāϞāĻŋ āϰāĻŋāĻĒā§‹āĻ°ā§āϟ/āĻŦāĻŋāϞāĻŋāĻ‚ āϜāĻŦ(CRON) āϰāĻžāύ āĻšāĻ“āϝāĻŧāĻžāϰ āĻ•āĻĨāĻž āĻ›āĻŋāϞāĨ¤ āĻ•āĻŋāĻ¨ā§āϤ⧁ āχāωāϜāĻžāϰāϰāĻž āϰāĻŋāĻĒā§‹āĻ°ā§āϟ āĻ•āϰāϞ⧋ āϝ⧇ āϰāĻŋāĻĒā§‹āĻ°ā§āϟ āĻ•āĻ–āύ⧋ ā§Ŧ āϘāĻŖā§āϟāĻž āφāϗ⧇, āĻ•āĻ–āύ⧋ ā§Ŧ āϘāĻŖā§āϟāĻž āĻĒāϰ⧇ āφāϏāϛ⧇ — āĻ•āĻ–āύ⧋ āĻ•āĻ–āύ⧋ āĻĒ⧁āϰ⧋āĻĒ⧁āϰāĻŋ āĻŽāĻŋāϏāĻŋāĻ‚, āφāĻŦāĻžāϰ āĻ•āĻ–āύ⧋ āĻāĻ•āχ āĻĻāĻŋāύ⧇ āĻĻ⧁āχāĻŦāĻžāϰ āϰāĻžāύ āĻšāϝāĻŧ⧇ āϝāĻžāĻšā§āϛ⧇āĨ¤

🔍 Investigation Timeline

🧠 System āϕ⧀ āĻšāϝāĻŧ⧇āĻ›āĻŋāϞ, āφāϏāϞ⧇

āĻĒā§āϰāĻĨāĻŽā§‡ āĻŽāύ⧇ āĻšāϝāĻŧ⧇āĻ›āĻŋāϞ āϏāĻŽāĻ¸ā§āϝāĻžāϟāĻž billing calculation logic-āĻāχ āφāϛ⧇ — āĻšāϝāĻŧāϤ⧋ usage aggregation query āϭ⧁āϞ date range āϧāϰāϛ⧇āĨ¤ āϟāĻŋāĻŽ āĻĒā§āϰāĻĨāĻŽ āĻ•āĻŋāϛ⧁ āϏāĻŽāϝāĻŧ query-āχ āϰāĻŋāĻ­āĻŋāω āĻ•āϰāϞ⧋āĨ¤

āĻ•āĻŋāĻ¨ā§āϤ⧁ āφāϏāϞ āϏāĻŽāĻ¸ā§āϝāĻžāϟāĻž query-āϤ⧇ āĻ›āĻŋāϞ⧋āχ āύāĻžāĨ¤ āĻĄā§‡āϭ⧇āϞāĻĒāĻžāϰ āύāĻŋāĻœā§‡āϰ āĻŽāĻžāĻĨāĻžāϰ āϟāĻžāχāĻŽāĻœā§‹āύ āϧāϰ⧇ cron āĻāĻ•ā§āϏāĻĒā§āϰ⧇āĻļāύ āϞāĻŋāĻ–āϞ⧋ → āϏāĻŋāĻ¸ā§āĻŸā§‡āĻŽ cron āϏ⧇āϟāĻžāϕ⧇ OS/āĻ•āĻ¨ā§āĻŸā§‡āχāύāĻžāϰ⧇āϰ āϟāĻžāχāĻŽāĻœā§‹āύ⧇ āχāĻ¨ā§āϟāĻžāϰāĻĒā§āϰ⧇āϟ āĻ•āϰāϞ⧋ (āϏāĻžāϧāĻžāϰāĻŖāϤ UTC) → āĻŽāĻŋāϏāĻŽā§āϝāĻžāϚ → āϜāĻŦ āϭ⧁āϞ āϏāĻŽāϝāĻŧ⧇ āĻĢāĻžāϝāĻŧāĻžāϰ āĻšāϞ⧋ → āĻāϰ āĻĄāĻžāωāύāĻ¸ā§āĻŸā§āϰāĻŋāĻŽ āĻĒā§āϰāĻ­āĻžāĻŦ (āĻĄāĻžāĻŦāϞ-āϚāĻžāĻ°ā§āϜāĻŋāĻ‚, āĻŽāĻŋāϏāĻŋāĻ‚ āĻĄā§‡āχāϞāĻŋ āϰāĻŋāĻĒā§‹āĻ°ā§āϟ, āĻ…āĻ¨ā§āϝ āϜāĻŦ⧇āϰ āϏāĻžāĻĨ⧇ āĻ…āĻ°ā§āĻĄāĻžāϰ āύāĻŋāϝāĻŧ⧇ āϰ⧇āϏ āĻ•āĻ¨ā§āĻĄāĻŋāĻļāύ)āĨ¤

# āĻĄā§‡āϭ⧇āϞāĻĒāĻžāϰ āϝāĻž āϭ⧇āĻŦ⧇āĻ›āĻŋāϞ⧇āύ:
0 0 * * *  →  "āϰāĻžāϤ ⧧⧍āϟāĻž, āĻŽāĻžāύ⧇ Dhaka midnight"

# cron daemon āϝāĻž āφāϏāϞ⧇ āĻ•āϰāϞ⧋:
0 0 * * *  →  "00:00 UTC"  =  "06:00 AM Dhaka time" (ā§Ŧ āϘāĻŖā§āϟāĻž āĻĒāĻžāĻ°ā§āĻĨāĻ•ā§āϝ)

đŸ› ī¸ āϝ⧇āĻ­āĻžāĻŦ⧇ āĻ āĻŋāĻ• āĻ•āϰāĻž āĻšāϞ⧋

const cron = require("node-cron");

cron.schedule(
  "0 0 * * *",
  () => runDailyBilling(),
  { timezone: "Asia/Dhaka" }
);
timedatectl set-timezone UTC

🧠 āφāϏāϞ āĻļāĻŋāĻ•ā§āώāĻž

🌐 Web Server & Routing Scenarios

The SPA Refresh 404 (Nginx Routing Mismatch)

📌 Incident Summary

Field Detail
Time Deploy-āĻāϰ āĻĒāϰ⧇āϰ āĻĻāĻŋāύ, āϏāĻ•āĻžāϞ
Symptom /dashboard-āĻ refresh āĻĻāĻŋāϞ⧇āχ 404, āĻ•āĻŋāĻ¨ā§āϤ⧁ āϏāϰāĻžāϏāϰāĻŋ homepage āĻĨ⧇āϕ⧇ navigate āĻ•āϰāϞ⧇ āĻ āĻŋāĻ•āĻ āĻžāĻ• āĻ•āĻžāϜ āĻ•āϰ⧇
Root Cause Nginx file-system-āĻ­āĻŋāĻ¤ā§āϤāĻŋāĻ• routing āφāĻļāĻž āĻ•āϰāĻ›āĻŋāϞ, āĻ•āĻŋāĻ¨ā§āϤ⧁ SPA route āϗ⧁āϞ⧋ client-side JavaScript-āĻ resolve āĻšāĻšā§āĻ›āĻŋāϞ — āϏāĻžāĻ°ā§āĻ­āĻžāϰ⧇ āϏ⧇āχ path-āĻāϰ āϕ⧋āύ⧋ āĻĢāĻžāχāϞ āύ⧇āχ
Resolution try_files directive āĻĻāĻŋāϝāĻŧ⧇ āϏāĻŦ unknown route-āϕ⧇ index.html-āĻ fallback āĻ•āϰāĻžāύ⧋
Severity 🟠 High (user-facing, āĻ•āĻŋāĻ¨ā§āϤ⧁ data loss āύ⧇āχ)

📟 Alert

“āĻ­āĻžāχ, dashboard page refresh āĻĻāĻŋāϞ⧇āχ 404 āĻĻ⧇āĻ–āĻžāĻšā§āϛ⧇āĨ¤ āĻ•āĻŋāĻ¨ā§āϤ⧁ āϞāĻŋāĻ‚āϕ⧇ āĻ•ā§āϞāĻŋāĻ• āĻ•āϰāϞ⧇ āĻ āĻŋāĻ•āχ āĻ•āĻžāϜ āĻ•āϰ⧇!”

āĻāχ āϧāϰāύ⧇āϰ bug report āĻļ⧁āύāϞ⧇ āĻĒā§āϰāĻĨāĻŽā§‡ āĻŽāύ⧇ āĻšāϝāĻŧ frontend routing-āĻ āϕ⧋āύ⧋ bug āφāϛ⧇āĨ¤ āĻ•āĻŋāĻ¨ā§āϤ⧁ āφāϏāϞ āϏāĻŽāĻ¸ā§āϝāĻž client āĻāĻŦāĻ‚ server — āĻĻ⧁āχ āϜāĻžāϝāĻŧāĻ—āĻžāϝāĻŧ route āĻŦā§‹āĻāĻžāϰ āĻĻ⧁āχāϟāĻž āϏāĻŽā§āĻĒā§‚āĻ°ā§āĻŖ āφāϞāĻžāĻĻāĻž āĻŽāĻĄā§‡āϞ⧇āϰ āĻŽāĻ§ā§āϝ⧇āĨ¤


🔍 Investigation Timeline

Step 1 — Browser āĻĨ⧇āϕ⧇ āĻĒā§āϰāĻĨāĻŽ āĻĒāĻ°ā§āϝāĻŦ⧇āĻ•ā§āώāĻŖ

example.com → click "Dashboard" link → example.com/dashboard āϞ⧋āĻĄ āĻšāϝāĻŧ

āϕ⧋āύ⧋ problem āύ⧇āχāĨ¤ URL āĻŦāĻĻāϞ⧇āϛ⧇, page-āĻ“ āĻŦāĻĻāϞ⧇āϛ⧇āĨ¤

example.com/dashboard → press F5 (refresh)

→ 404 Not Found

👉 āĻāĻ•āχ URL, āĻ•āĻŋāĻ¨ā§āϤ⧁ āĻāĻ•āĻŦāĻžāϰ āĻ•āĻžāϜ āĻ•āϰāϛ⧇, āĻāĻ•āĻŦāĻžāϰ āĻ•āϰāϛ⧇ āύāĻžāĨ¤ āĻŽāĻžāύ⧇ āϏāĻŽāĻ¸ā§āϝāĻžāϟāĻž route āύāĻŋāĻœā§‡ āύāϝāĻŧ — āϏāĻŽāĻ¸ā§āϝāĻž āĻšāϞ⧋ āϕ⧀āĻ­āĻžāĻŦ⧇ āĻāχ route-āĻ āĻĒ⧌āρāĻ›āĻžāύ⧋ āĻšāĻšā§āϛ⧇āĨ¤

Step 2 — Network Tab āϖ⧁āρāϟāĻŋāϝāĻŧ⧇ āĻĻ⧇āĻ–āĻž

āĻ•ā§āϞāĻŋāĻ• āĻ•āϰāĻžāϰ āϏāĻŽāϝāĻŧ:

No network request sent for /dashboard

Refresh āĻ•āϰāĻžāϰ āϏāĻŽāϝāĻŧ:

GET /dashboard → 404

👉 āĻāĻ–āĻžāύ⧇āχ clue āĻĒāĻžāĻ“āϝāĻŧāĻž āϗ⧇āϞ — link click-āĻāϰ āϏāĻŽāϝāĻŧ āϕ⧋āύ⧋ HTTP request-āχ Nginx āĻĒāĻ°ā§āϝāĻ¨ā§āϤ āϝāĻžāĻšā§āϛ⧇ āύāĻžāĨ¤ āĻĒ⧁āϰ⧋āϟāĻžāχ browser-āĻāϰ āϭ⧇āϤāϰ⧇ handle āĻšāĻšā§āϛ⧇āĨ¤

Step 3 — Nginx Config āĻšā§‡āĻ• āĻ•āϰāĻž

cat /etc/nginx/sites-available/default
location / {
  try_files $uri $uri/ =404;
}

👉 āĻĒāĻžāĻ“āϝāĻŧāĻž āϗ⧇āϞ āφāϏāϞ āĻ•āĻžāϰāĻŖ — =404 āĻŽāĻžāύ⧇ Nginx-āϕ⧇ āĻŦāϞāĻž āφāϛ⧇, file āĻŦāĻž directory āύāĻž āĻĒāĻžāĻ“āϝāĻŧāĻž āϗ⧇āϞ⧇ āϏāϰāĻžāϏāϰāĻŋ 404 āĻĢ⧇āϰāϤ āĻĻāĻŋāϤ⧇āĨ¤ Nginx-āĻāϰ āĻ•āĻžāϛ⧇ /dashboard āĻŽāĻžāύ⧇ disk-āĻ āĻĨāĻžāĻ•āĻž āĻāĻ•āϟāĻž āĻĢāĻžāχāϞ āĻŦāĻž āĻĢā§‹āĻ˛ā§āĻĄāĻžāϰ — āϝāĻž āφāĻĻāϤ⧇ āĻ•āĻ–āύ⧋ āĻŦāĻžāύāĻžāύ⧋āχ āĻšāϝāĻŧāύāĻŋāĨ¤


🧠 System āϕ⧀ āĻšāϝāĻŧ⧇āĻ›āĻŋāϞ, āφāϏāϞ⧇

āĻāϟāĻž āϕ⧋āύ⧋ crash āĻŦāĻž bug āύāĻž — āĻāϟāĻž āĻĻ⧁āχ layer-āĻāϰ routing model-āĻāϰ āĻŽāĻ§ā§āϝ⧇ āĻāĻ•āϟāĻž mismatchāĨ¤

Browser āĻāĻ•āϟāĻž link-āĻ click āĻ•āϰ⧇
→ React Router URL āĻŦāĻĻāϞ⧇ āĻĻ⧇āϝāĻŧ (pushState)
→ āϕ⧋āύ⧋ server request āϝāĻžāϝāĻŧāχ āύāĻž
→ Component client-side render āĻšāϝāĻŧ
→ āϏāĻŦ āĻ āĻŋāĻ•āĻ āĻžāĻ• āĻĻ⧇āĻ–āĻžāϝāĻŧ

āĻ•āĻŋāĻ¨ā§āϤ⧁ refresh āĻ•āϰāϞ⧇:
→ Browser āĻāĻ•āĻĻāĻŽ fresh GET request āĻĒāĻžāĻ āĻžāϝāĻŧ
→ Nginx āϏ⧇āχ path-āϕ⧇ āĻĢāĻžāχāϞ-āϏāĻŋāĻ¸ā§āĻŸā§‡āĻŽ path āĻšāĻŋāϏ⧇āĻŦ⧇ treat āĻ•āϰ⧇
→ /dashboard āύāĻžāĻŽā§‡ āϕ⧋āύ⧋ āĻĢāĻžāχāϞ āĻŦāĻž folder āύ⧇āχ
→ Nginx 404 āĻĢ⧇āϰāϤ āĻĻ⧇āϝāĻŧ — JavaScript āϞ⧋āĻĄ āĻšāĻ“āϝāĻŧāĻžāϰ āϏ⧁āϝ⧋āĻ—āχ āĻĒāĻžāϝāĻŧ āύāĻž

Nginx āϭ⧁āϞ āĻ•āĻŋāϛ⧁ āĻ•āϰ⧇āύāĻŋ — āϏ⧇ āύāĻŋāĻœā§‡āϰ āύāĻŋāϝāĻŧāĻŽ āĻ…āύ⧁āϝāĻžāϝāĻŧā§€ āĻ āĻŋāĻ•āχ āĻ•āĻžāϜ āĻ•āϰāϛ⧇āĨ¤ āϏāĻŽāĻ¸ā§āϝāĻž āĻšāϞ⧋, SPA routing model-āĻāϰ āϏāĻžāĻĨ⧇ āĻāχ āύāĻŋāϝāĻŧāĻŽāϟāĻž āĻ•āĻ–āύ⧋ align āĻ•āϰāĻžāύ⧋āχ āĻšāϝāĻŧāύāĻŋāĨ¤


🔗 Root Cause Chain

SPA deploy āĻ•āϰāĻž āĻšāϝāĻŧ (client-side routing āϏāĻš)
→ Nginx config-āĻ āĻļ⧁āϧ⧁ literal file/folder lookup āφāϛ⧇
→ Client navigation request āĻĒāĻžāĻ āĻžāϝāĻŧ āύāĻž (JS intercept āĻ•āϰ⧇)
→ Refresh/direct-URL hit āϏāϰāĻžāϏāϰāĻŋ Nginx-āϕ⧇ āφāϏāϞ path āϜāĻŋāĻœā§āĻžā§‡āϏ āĻ•āϰ⧇
→ āĻĄāĻŋāĻ¸ā§āϕ⧇ āϏ⧇āχ path-āĻāϰ āϕ⧋āύ⧋ file āύ⧇āχ
→ try_files $uri $uri/ =404 fallback āĻŸā§āϰāĻŋāĻ—āĻžāϰ āĻšāϝāĻŧ
→ Nginx 404 āĻĒāĻžāĻ āĻžāϝāĻŧ, index.html āĻ•āĻ–āύ⧋ āϞ⧋āĻĄ āĻšāϝāĻŧ āύāĻž
→ React Router-āĻāϰ āϏ⧁āϝ⧋āĻ—āχ āĻĨāĻžāϕ⧇ āύāĻž route resolve āĻ•āϰāĻžāϰ

đŸ› ī¸ āϝ⧇āĻ­āĻžāĻŦ⧇ āĻ āĻŋāĻ• āĻ•āϰāĻž āĻšāϞ⧋

server {
  listen 80;
  server_name example.com;
  root /var/www/my-spa-app;
  index index.html;

  location / {
    try_files $uri $uri/ /index.html;
  }
}
sudo nginx -t
sudo systemctl reload nginx

try_files āϧāĻžāĻĒ⧇ āϧāĻžāĻĒ⧇ āϝāĻž āĻ•āϰ⧇

  1. $uri — exact file āφāϛ⧇ āĻ•āĻŋāύāĻž āĻšā§‡āĻ• āĻ•āϰ⧇ (āϝ⧇āĻŽāύ logo.png)āĨ¤ āĻĨāĻžāĻ•āϞ⧇ āϏāϰāĻžāϏāϰāĻŋ serve āĻ•āϰ⧇āĨ¤
  2. $uri/ — file āύāĻž āĻšāϞ⧇ directory āĻ•āĻŋāύāĻž āĻšā§‡āĻ• āĻ•āϰ⧇āĨ¤
  3. /index.html — āϕ⧋āύ⧋āϟāĻžāχ āύāĻž āĻĨāĻžāĻ•āϞ⧇ (āϝ⧇āĻŽāύ /dashboard), index.html āĻĢ⧇āϰāϤ āĻĻ⧇āϝāĻŧāĨ¤ Browser SPA āϞ⧋āĻĄ āĻ•āϰ⧇, client-side router URL āĻĻ⧇āϖ⧇ āĻ āĻŋāĻ• component āĻŦāĻžāύāĻžāϝāĻŧāĨ¤

āĻĢāϞāĻžāĻĢāϞ: refresh āĻ•āϰāϞ⧇āĻ“ āφāϰ 404 āφāϏ⧇ āύāĻž, āĻ•āĻžāϰāĻŖ Nginx āĻāĻ–āύ routing decision client-side JavaScript-āĻāϰ āĻšāĻžāϤ⧇ āϛ⧇āĻĄāĻŧ⧇ āĻĻ⧇āϝāĻŧ, āύāĻŋāĻœā§‡ judge āĻ•āϰāĻžāϰ āĻšā§‡āĻˇā§āϟāĻž āĻ•āϰ⧇ āύāĻžāĨ¤


âš ī¸ Hidden Failure Mode

“āϝāĻĻāĻŋ āĻ•ā§āϞāĻŋāĻ• āĻ•āϰ⧇ āĻ•āĻžāϜ āĻ•āϰ⧇, āϤāĻžāĻšāϞ⧇ route-āϟāĻž āĻ āĻŋāĻ• āφāĻ›ā§‡â€ — āĻāχ assumption-āϟāĻžāχ āĻŦāĻŋāĻ­ā§āϰāĻžāĻ¨ā§āϤāĻŋāĻ•āϰāĨ¤

Client-side navigation āφāϰ server-side request — āĻāχ āĻĻ⧁āĻŸā§‹ āϏāĻŽā§āĻĒā§‚āĻ°ā§āĻŖ āφāϞāĻžāĻĻāĻž pathāĨ¤ QA-āϤ⧇ āϝāĻĻāĻŋ āϕ⧇āω āĻļ⧁āϧ⧁ click āĻ•āϰ⧇ test āĻ•āϰ⧇, refresh āĻ•āĻ–āύ⧋ āύāĻž āĻ•āϰ⧇, āĻāχ bug āĻĒā§āϰ⧋āĻĄāĻžāĻ•āĻļāύ⧇ āϝāĻžāĻ“āϝāĻŧāĻž āĻĒāĻ°ā§āϝāĻ¨ā§āϤ āϧāϰāĻžāχ āĻĒāĻĄāĻŧāĻŦ⧇ āύāĻžāĨ¤ āφāϰ deep-link āĻļ⧇āϝāĻŧāĻžāϰ āĻ•āϰāĻž (āĻ•āĻžāωāϕ⧇ āϏāϰāĻžāϏāϰāĻŋ /dashboard āϞāĻŋāĻ‚āĻ• āĻĒāĻžāĻ āĻžāύ⧋) āĻāĻ•āχ āĻ•āĻžāϰāϪ⧇ āϭ⧇āϙ⧇ āϝāĻžāĻŦ⧇ — āĻ•āĻžāϰāĻŖ āϏ⧇āϟāĻžāĻ“ āĻāĻ•āϟāĻž fresh server requestāĨ¤



## 🧨 Common Gotchas (Fix āĻ•āϰāĻžāϰ āĻĒāϰ⧇āĻ“ āϝāĻž āĻŽāĻžāĻĨāĻžāϝāĻŧ āϰāĻžāĻ–āϤ⧇ āĻšāĻŦ⧇)

### 1. Real 404 āĻšāĻžāϰāĻŋāϝāĻŧ⧇ āϝāĻžāϝāĻŧ

example.com/this-route-does-not-exist-anywhere ```

āĻāĻ–āύ āĻāϟāĻžāĻ“ index.html-āĻ fallback āĻšāϝāĻŧ⧇ āϝāĻžāĻŦ⧇ — Nginx-level 404 āφāϰ āĻĻ⧇āĻ–āĻž āϝāĻžāĻŦ⧇ āύāĻžāĨ¤ āĻāϰ āĻŽāĻžāύ⧇ router āύāĻŋāĻœā§‡āχ āĻāĻ•āϟāĻž catch-all “Not Found” route define āĻ•āϰāϤ⧇ āĻšāĻŦ⧇, āύāĻžāĻšāϞ⧇ user āĻāĻ•āϟāĻž broken page-āϕ⧇ valid page āϭ⧇āĻŦ⧇ āĻŦāϏ⧇ āĻĨāĻžāĻ•āĻŦ⧇āĨ¤

2. index.html Caching

index.html āϝāĻĻāĻŋ aggressively cache āĻšāϝāĻŧ, āύāϤ⧁āύ deploy āĻ•āϰāĻžāϰ āĻĒāϰ⧇āĻ“ user āĻĒ⧁āϰāύ⧋ JS bundle reference āĻ•āϰāĻž version āĻĻ⧇āĻ–āϤ⧇ āĻĨāĻžāĻ•āĻŦ⧇āĨ¤ index.html-āĻāϰ āϜāĻ¨ā§āϝ Cache-Control: no-cache āϰāĻžāĻ–āĻž āĻ­āĻžāϞ⧋, āφāϰ static asset (JS/CSS bundle)-āĻāϰ āϜāĻ¨ā§āϝ hashed filename + long-term cachingāĨ¤


🧠 āφāϏāϞ āĻļāĻŋāĻ•ā§āώāĻž

Server āĻ•āĻ–āύ⧋ āϜāĻžāύ⧇ āύāĻž client-side router-āĻāϰ āϭ⧇āϤāϰ⧇ āϕ⧀ āϕ⧀ route define āĻ•āϰāĻž āφāϛ⧇ — āϤāĻžāχ āϤāĻžāϕ⧇ āĻŦāϞ⧇ āĻĻāĻŋāϤ⧇ āĻšāϝāĻŧ, “āϤ⧋āĻŽāĻžāϰ āϝāĻž āĻšā§‡āύāĻžāϰ āĻ•āĻĨāĻž āύāĻž, āϏ⧇āϟāĻžāϰ fallback āĻĻāĻŋāϝāĻŧ⧇ āĻĻāĻŋāĻ“āĨ¤â€