الوضعين · فصل ٢

Fork Mode — كل Process في حالها

child_process.fork · Nginx upstream · increment_var
🎯 الهدف: تبني fork بإيدك وبـ PM2، وتفهم ليه كل process محتاجة port مختلف وحد قدامها يوزّع.

الفكرة

في fork، كل instance بتبقى process مستقلة: ليها memory لوحدها، وevent loop لوحده، وفي الغالب port لوحده. مفيش أي حاجة مشتركة بين الـ processes.

الـ processes مش بتتقاسم port، فلازم حد قدامهم يوزّع الطلبات عليهم. والحد ده غالبًا Nginx.

fork: كل process على port
  1. Client ← Nginx: request
  2. Nginx ← process 1
  3. Nginx ← process 2
  4. Nginx ← process 3

بإيدك: سكريبت بيشغّل 3 processes

fork-launcher.js
const { fork } = require("node:child_process");const ports = [3001, 3002, 3003];for (const port of ports) {  // كل واحدة process جديدة تمامًا، وبناخد الـ port من env  const child = fork("./server.js", [], {    env: { ...process.env, PORT: String(port) },  });  child.on("exit", (code) => console.log(`port ${port} exited with ${code}`));}

السكريبت ده بيعمل fork وبس: مش بيرجّع process لو وقعت، ومش بيوزّع طلبات. وعشان العميل يكلم port واحد، محتاج Nginx:

/etc/nginx/conf.d/app.conf
upstream app {  server 127.0.0.1:3001;  server 127.0.0.1:3002;  server 127.0.0.1:3003;}server {  listen 80;  location / {    proxy_pass http://app;  }}

نفس الكلام بـ PM2

بدل السكريبت، PM2 بيشغّل الـ processes ويرجّع أي واحدة تقع. والمشكلة إن كلهم هيقروا نفس PORT، فنستخدم increment_var:

ecosystem.config.js
module.exports = {  apps: [    {      name: "api-fork",      script: "./server.js",      exec_mode: "fork",      instances: 3,      increment_var: "PORT", // 3001، 3002، 3003      env: { PORT: 3001 },    },  ],};
terminal
pm2 start ecosystem.config.jspm2 list                         # عمود mode = forkcurl localhost:3001; curl localhost:3002; curl localhost:3003
  • PM2 بيزوّد PORT بواحد لكل instance جديدة.
  • لو نسيت increment_var، كلهم هيحاولوا يفتحوا 3001، والتانية والتالتة هيقعوا بـ EADDRINUSE.
  • Nginx لسه مطلوب قدامهم. PM2 في fork مش بيوزّع ترافيك.

خلّصت الفصل لما

🧠 اختبر نفسك
١) 3 instances fork من غير increment_var على PORT=3001. إيه اللي هيحصل؟
واحدة بس هتفتح 3001، والاتنين التانيين هيقعوا بـ EADDRINUSE وPM2 هيفضل يعيد تشغيلهم.
٢) مين بيوزّع الطلبات في fork؟
حد برّه PM2، زي Nginx أو load balancer.
٣) عندي worker بيسحب jobs من Redis. fork ولا cluster؟
fork، لأنه مش بيسمع على port، وcluster ميزته الأساسية تقسيم الـ port.