إدارة عملية PM2 لـ Node.js في الإنتاج
عندما يتعطل تطبيق Node.js الخاص بك في الساعة 2 صباحًا، فإن PM2 هو الفرق بين إعادة تشغيله تلقائيًا ورؤية المستخدمين لديك لصفحة فارغة حتى تستيقظ. PM2 هو مدير عمليات تم اختباره في المعركة ويتعامل مع عمليات إعادة التشغيل التلقائية، والتجميع للاستخدام متعدد النواة، وتجميع السجلات، وعمليات النشر بدون توقف - كل ذلك باستخدام ملف تكوين واحد موجود في مستودعك.
يغطي هذا الدليل إعداد PM2 الإنتاجي الذي يدير 5 عمليات Node.js في وقت واحد: Next.js (الواجهة الأمامية)، وNestJS (API)، وDocusaurus (docs)، وموقعين للعلامات التجارية. تنطبق الأنماط بالتساوي على عمليات النشر ذات العملية الواحدة.
الوجبات الرئيسية
- الملف
ecosystem.config.cjs(CommonJS، وليس.js) يعمل مع كل من مشروعي ESModule وCommonJS- علامة
--update-envمطلوبة عند إعادة التشغيل لالتقاط متغيرات البيئة الجديدة- لا تستخدم
pm2 restart allمطلقًا بدون--update-envبعد تحديث.env.localwatch: falseفي الإنتاج - تؤدي مشاهدة الملفات إلى حلقات إعادة تشغيل لا حصر لها مع مخرجات البناءmax_memory_restartيوفر حماية تلقائية من تسرب الذاكرة دون إنهاء العملية بشكل دائمnode_args: '--max-old-space-size=4096'يمنع تعطل OOM في العمليات كثيفة الاستهلاك للذاكرة- تدور سجلات PM2 باستخدام الوحدة
pm2-logrotate- قم بتثبيتها مباشرة بعد PM2 نفسهاpm2 saveوpm2 startupيستمران في قائمة العمليات الخاصة بك عبر عمليات إعادة تشغيل الخادم
التثبيت
# Install PM2 globally
npm install -g pm2
# Install the log rotation module immediately
pm2 install pm2-logrotate
# Configure log rotation
pm2 set pm2-logrotate:max_size 50M
pm2 set pm2-logrotate:retain 7
pm2 set pm2-logrotate:compress true
pm2 set pm2-logrotate:dateFormat YYYY-MM-DD
ملف تكوين النظام البيئي
يحدد الملف ecosystem.config.cjs (تنسيق CommonJS للعمل مع مشروعي ESM وCJS) جميع عملياتك:
// ecosystem.config.cjs
module.exports = {
apps: [
// ─── Next.js Frontend ────────────────────────────────────────────
{
name: 'ecosire-web',
script: 'node_modules/.bin/next',
args: 'start',
cwd: '/opt/ecosire/app/apps/web',
instances: 1, // Single instance — Next.js handles its own multi-threading
exec_mode: 'fork',
env: {
NODE_ENV: 'production',
PORT: 3000,
},
// Memory management
max_memory_restart: '1G',
node_args: '--max-old-space-size=1024',
// Logging
out_file: '/var/log/pm2/ecosire-web.out.log',
error_file: '/var/log/pm2/ecosire-web.err.log',
merge_logs: true,
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
// Restart behavior
watch: false,
restart_delay: 3000,
max_restarts: 10,
min_uptime: '30s', // Must stay up 30s to count as successful start
autorestart: true,
// Graceful shutdown
kill_timeout: 30000, // 30 seconds to shut down gracefully
wait_ready: true, // Wait for process.send('ready')
listen_timeout: 60000,
},
// ─── NestJS API ──────────────────────────────────────────────────
{
name: 'ecosire-api',
script: 'dist/main.js',
cwd: '/opt/ecosire/app/apps/api',
instances: 2, // Cluster mode for multi-core utilization
exec_mode: 'cluster',
env: {
NODE_ENV: 'production',
PORT: 3001,
},
max_memory_restart: '512M',
node_args: '--max-old-space-size=512',
out_file: '/var/log/pm2/ecosire-api.out.log',
error_file: '/var/log/pm2/ecosire-api.err.log',
merge_logs: true,
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
watch: false,
restart_delay: 2000,
max_restarts: 10,
min_uptime: '20s',
autorestart: true,
kill_timeout: 15000,
// Graceful cluster reload support
listen_timeout: 30000,
},
// ─── Docusaurus Docs ─────────────────────────────────────────────
{
name: 'ecosire-docs',
script: 'node_modules/.bin/docusaurus',
args: 'serve',
cwd: '/opt/ecosire/app/apps/docs',
instances: 1,
exec_mode: 'fork',
env: {
NODE_ENV: 'production',
PORT: 3002,
},
max_memory_restart: '256M',
out_file: '/var/log/pm2/ecosire-docs.out.log',
error_file: '/var/log/pm2/ecosire-docs.err.log',
merge_logs: true,
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
watch: false,
restart_delay: 3000,
max_restarts: 5,
min_uptime: '30s',
autorestart: true,
kill_timeout: 10000,
},
// ─── Brand Site: Odovation ───────────────────────────────────────
{
name: 'odovation-web',
script: 'node_modules/.bin/next',
args: 'start',
cwd: '/opt/ecosire/app/apps/odovation',
instances: 1,
exec_mode: 'fork',
env: {
NODE_ENV: 'production',
PORT: 3010,
},
max_memory_restart: '512M',
out_file: '/var/log/pm2/odovation-web.out.log',
error_file: '/var/log/pm2/odovation-web.err.log',
merge_logs: true,
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
watch: false,
restart_delay: 3000,
max_restarts: 10,
min_uptime: '30s',
autorestart: true,
},
// ─── Brand Site: MuhammadAmir ────────────────────────────────────
{
name: 'muhammadamir-web',
script: 'node_modules/.bin/next',
args: 'start',
cwd: '/opt/ecosire/app/apps/muhammadamir',
instances: 1,
exec_mode: 'fork',
env: {
NODE_ENV: 'production',
PORT: 3020,
},
max_memory_restart: '512M',
out_file: '/var/log/pm2/muhammadamir-web.out.log',
error_file: '/var/log/pm2/muhammadamir-web.err.log',
merge_logs: true,
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
watch: false,
restart_delay: 3000,
max_restarts: 10,
min_uptime: '30s',
autorestart: true,
},
],
};
أوامر PM2 الأساسية
# Start all processes from ecosystem file
pm2 start ecosystem.config.cjs
# Restart all (with updated environment variables)
pm2 restart ecosystem.config.cjs --update-env
# Graceful reload (zero-downtime for cluster mode)
pm2 reload ecosystem.config.cjs
# Stop all processes
pm2 stop all
# Delete all processes from PM2 registry
pm2 delete all
# Individual process management
pm2 restart ecosire-api
pm2 stop ecosire-docs
pm2 logs ecosire-web --lines 100
# Real-time monitoring dashboard
pm2 monit
# Status overview
pm2 status
pm2 list
بدء التشغيل عند إعادة تشغيل الخادم
بدون تكوين بدء التشغيل، سيتم فقدان جميع عمليات PM2 عند إعادة تشغيل الخادم:
# Generate and install the startup script for your init system
pm2 startup
# Copy the output command and run it (it looks like:)
# sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u ubuntu --hp /home/ubuntu
# Save the current process list
pm2 save
# This creates ~/.pm2/dump.pm2 — processes are restored on reboot
# Verify startup works
pm2 resurrect # Manually restore from dump.pm2
في كل مرة تقوم فيها بإضافة أو إزالة العمليات، قم بتشغيل pm2 save مرة أخرى لتحديث ملف التفريغ.
عمليات النشر بدون توقف
بالنسبة إلى NestJS في وضع المجموعة، يدعم PM2 عمليات إعادة التحميل الحقيقية بدون توقف:
# Reload restarts workers one at a time (zero-downtime)
# Old workers handle requests while new ones start
pm2 reload ecosire-api
# vs restart — kills all workers simultaneously (brief downtime)
pm2 restart ecosire-api
بالنسبة إلى Next.js (الذي يعمل في وضع التفرع، مثيل واحد)، يتطلب وقت التوقف الصفري أسلوبًا مختلفًا. استخدم التكوين wait_ready + listen_timeout مع إشارة بدء التشغيل من تطبيقك:
// apps/web — this is handled automatically by Next.js
// But for NestJS, send the ready signal explicitly:
// apps/api/src/main.ts
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3001);
// Signal PM2 that the process is ready
if (process.send) {
process.send('ready');
}
}
bootstrap();
إدارة السجل
يمكن أن تملأ سجلات PM2 القرص الخاص بك إذا لم تتم إدارتها. تكوين دوران السجل على الفور:
# Install log rotation module
pm2 install pm2-logrotate
# Configuration
pm2 set pm2-logrotate:max_size 50M # Rotate when log reaches 50MB
pm2 set pm2-logrotate:retain 7 # Keep 7 days of logs
pm2 set pm2-logrotate:compress true # Gzip rotated logs
pm2 set pm2-logrotate:dateFormat YYYY-MM-DD
pm2 set pm2-logrotate:workerInterval 30 # Check rotation interval (seconds)
pm2 set pm2-logrotate:rotateInterval '0 0 * * *' # Daily at midnight
أوامر السجل المفيدة:
# View all logs combined
pm2 logs
# View specific process logs
pm2 logs ecosire-api
# View with timestamps
pm2 logs --timestamp
# Flush all log files
pm2 flush
# Tail error logs only
pm2 logs ecosire-api --err --lines 200
المراقبة والمقاييس
يوفر PM2 Plus (المعروف سابقًا باسم Keymetrics) مراقبة قائمة على السحابة. للمراقبة ذاتية الاستضافة:
# Built-in terminal dashboard
pm2 monit
# Get JSON status for scripting/monitoring integration
pm2 jlist # JSON process list
pm2 prettylist # Formatted process list
# Integrate with your monitoring stack
pm2 set pm2-server-monit:interval 5 # Metrics collection interval
لمراقبة الإنتاج، قم بكشف مقاييس PM2 إلى Prometheus:
npm install -g pm2-prometheus-exporter
pm2 set pm2-prometheus-exporter:port 9209
# Scrape in Prometheus config:
# - job_name: pm2
# static_configs:
# - targets: ['localhost:9209']
تكامل البرنامج النصي للنشر
تسلسل النشر النموذجي:
#!/bin/bash
# scripts/deploy-production.sh
set -e
echo "=== Starting deployment ==="
# 1. Pull latest code
git pull origin main
# 2. Install dependencies
pnpm install --frozen-lockfile
# 3. Build all apps (with Turbo remote cache)
TURBO_TOKEN="$TURBO_TOKEN" TURBO_TEAM="$TURBO_TEAM" \
npx turbo run build
# 4. Run database migrations
pnpm --filter @ecosire/db db:migrate
# 5. Restart PM2 processes
# --update-env picks up changes in .env.local
pm2 restart ecosystem.config.cjs --update-env
# 6. Wait for processes to stabilize
sleep 10
# 7. Health checks
curl -f https://ecosire.com/ -o /dev/null -s || {
echo "Web health check failed — rolling back"
git revert HEAD --no-edit
pm2 restart ecosystem.config.cjs --update-env
exit 1
}
curl -f https://api.ecosire.com/api/health -o /dev/null -s || {
echo "API health check failed — rolling back"
git revert HEAD --no-edit
pm2 restart ecosystem.config.cjs --update-env
exit 1
}
# 8. Save process state
pm2 save
echo "=== Deployment complete ==="
المخاطر والحلول الشائعة
المأزق 1: نسيان --update-env
بعد تحديث .env.local، يؤدي تشغيل pm2 restart all بدون --update-env إلى إعادة تشغيل العمليات باستخدام متغيرات البيئة القديمة. استخدم دائمًا pm2 restart ecosystem.config.cjs --update-env.
المأزق 2: استخدام watch: true في الإنتاج
watch: true يعيد تشغيل العملية عند تغيير أي ملف. في الإنتاج، تتغير مخرجات البناء في كل عملية نشر - وهذا يؤدي إلى حلقات إعادة تشغيل لا حصر لها. قم دائمًا بتعيين watch: false.
المأزق 3: عدم التعامل مع SIGTERM لإيقاف التشغيل بسلاسة
يرسل PM2 SIGTERM عند إعادة التشغيل/الإيقاف. إذا لم يتعامل تطبيقك مع هذه المشكلة، فإن PM2 ينتظر kill_timeout مللي ثانية ويرسل SIGKILL - مما قد يتسبب في فقدان الطلبات. التعامل مع SIGTERM في NestJS:
// main.ts
const app = await NestFactory.create(AppModule);
await app.listen(3001);
// Graceful shutdown
process.on('SIGTERM', async () => {
await app.close();
process.exit(0);
});
المأزق 4: نفاد مساحة قرص سجل PM2
بدون pm2-logrotate، تنمو سجلات PM2 إلى أجل غير مسمى. يمكن لواجهة برمجة التطبيقات (API) التي يتم الاتجار بها بكثافة إنشاء غيغابايت من السجلات يوميًا. قم بتثبيت pm2-logrotate على الفور وقم بتعيين max_size (50 ميجابايت) وretain (7 أيام) بشكل معقول.
المأزق 5: فقدان العمليات بعد إعادة التشغيل
pm2 start لا يستمر في العمليات عبر عمليات إعادة التشغيل. قم دائمًا بتشغيل pm2 startup + pm2 save بعد الإعداد الأولي. إذا اختفت العمليات بعد إعادة التشغيل، قم بتشغيل pm2 resurrect للاستعادة من التفريغ المحفوظ.
الأسئلة المتداولة
متى يجب علي استخدام وضع المجموعة مقابل وضع الشوكة؟
استخدم وضع المجموعة لأحمال العمل المرتبطة بوحدة المعالجة المركزية (واجهات برمجة تطبيقات NestJS ذات العمليات الحسابية الثقيلة ومعالجة البيانات). يعمل الوضع العنقودي على توليد العمليات المنفذة instances وأرصدة تحميل PM2 فيما بينها - مع الاستفادة من جميع مراكز وحدة المعالجة المركزية. استخدم وضع التفرع لأحمال العمل المرتبطة بالإدخال/الإخراج (Next.js، خدمة الملفات الثابتة) أو عندما لا تدعم العملية التجميع (البرامج النصية ذات الترابط الواحد، خدمة Docusaurus). يتعامل Next.js مع مؤشرات الترابط العاملة الخاصة به داخليًا، لذا فإن وضع الشوكة مع instances: 1 هو الصحيح.
كيف يمكنني تشغيل PM2 في حاوية Docker؟
يستخدم PM2 في Docker pm2-docker (أو pm2-runtime) بدلاً من pm2 للتعامل مع الإشارات بشكل صحيح. لا يتم إخفاء إصدار وقت التشغيل (مما قد يتسبب في خروج Docker)، ويعيد توجيه الإشارات بشكل صحيح إلى العمليات الفرعية، ويسجل الدخول إلى stdout/stderr بدلاً من الملفات. استخدم CMD ["pm2-runtime", "ecosystem.config.cjs"] في ملف Dockerfile الخاص بك.
كيف يمكنني مراقبة عمليات PM2 من جهاز بعيد؟
توفر PM2 Plus (الخدمة السحابية للدفع لكل عملية) لوحة معلومات ويب. بالنسبة للمراقبة ذاتية الاستضافة، قم بكشف مقاييس PM2 عبر مصدر Prometheus وتصورها في Grafana. للتحقق من الحالة البسيطة، يمكنك SSH وتشغيل pm2 status، أو الكشف عن المقاييس عبر نقطة نهاية HTTP التي يستقصيها نظام المراقبة الخاص بك.
ما الفرق بين إعادة تحميل PM2 وإعادة تشغيل PM2؟
يقوم pm2 restart بقتل جميع العمال في وقت واحد وإعادة تشغيلهم - هناك فترة قصيرة لا يوجد فيها عمال قيد التشغيل (وقت التوقف عن العمل). pm2 reload رائع: فهو يبدأ عمالًا جددًا، وينتظرهم حتى يصبحوا جاهزين، ثم يوقف تشغيل العمال القدامى - بدون أي توقف عن العمل. استخدم pm2 reload لعمليات نشر الإنتاج. ملاحظة: إعادة التحميل تعمل بشكل صحيح فقط في وضع المجموعة؛ يعود وضع الشوكة إلى إعادة تشغيل السلوك.
كيف أقوم بتعيين متغيرات بيئة مختلفة لعمليات مختلفة؟
كل عملية في ecosystem.config.cjs لها أقسام env وenv_production الخاصة بها. يتم استخدام القسم env_production عند تمرير --env production إلى أوامر PM2. بالنسبة للأسرار، لا تضعها أبدًا مباشرة في ملف النظام البيئي - ضعها في بيئة النظام أو ملف .env.local ودع PM2 يرثها. تضمن العلامة --update-env أن يقوم PM2 بإعادة قراءة متغيرات البيئة عند إعادة التشغيل.
الخطوات التالية
يعد PM2 جزءًا أساسيًا من أي نشر لـ Node.js للإنتاج. يدير ECOSIRE 5 عمليات PM2 في الإنتاج — Next.js، وNestJS، وDocusaurus، وموقعين للعلامات التجارية — مع عمليات إعادة التشغيل التلقائية، وتدوير السجل، وعمليات النشر بدون توقف في كل مرة يتم فيها الضغط على المفتاح الرئيسي.
سواء كنت بحاجة إلى دعم DevOps الهندسي، أو بنية نشر الإنتاج، أو المساعدة في الترحيل إلى إعداد حاوية، استكشف خدماتنا لمعرفة كيف يمكننا مساعدتك.
بقلم
ECOSIRE TeamTechnical Writing
The ECOSIRE technical writing team covers Odoo ERP, Shopify eCommerce, AI agents, Power BI analytics, GoHighLevel automation, and enterprise software best practices. Our guides help businesses make informed technology decisions.
مقالات ذات صلة
AWS EC2 Deployment Guide for Web Applications
Complete AWS EC2 deployment guide: instance selection, security groups, Node.js deployment, Nginx reverse proxy, SSL, auto-scaling, CloudWatch monitoring, and cost optimization.
Zero-Downtime Database Migrations with Drizzle ORM
Run database migrations without downtime using Drizzle ORM. Covers expand-contract pattern, backward-compatible schema changes, rollback strategies, and CI/CD integration for PostgreSQL.
Next.js 16 App Router: Production Patterns and Pitfalls
Production-ready Next.js 16 App Router patterns: server components, caching strategies, metadata API, error boundaries, and performance pitfalls to avoid.