العناقيد في Node.js
الاستقرار: 2-مستقر
تعمل نسخةٌ واحدةٌ من Node.js في خيط (thread) واحد. للاستفادة من الأنظمة ذات الأنوية المتعدِّدة (multi-core)، سيضطر المستخدم حينها إلى تشغيل عنقود من عمليات Node.js لمعالجة الحمل.
تسمح الوحدة cluster
بإنشاء عمليات أبناء بسهولة تتشارك جميعها منافذ الخادم نفسها.
const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
console.log(`Master ${process.pid} is running`);
// (worker) تفريع مسار العمليات العاملة
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`worker ${worker.process.pid} died`);
});
} else {
// TCP تستطيع العمليات أن تتشارك أي اتصال
// http في هذه الحالة، الخادم هو خادم
http.createServer((req, res) => {
res.writeHead(200);
res.end('hello world\n');
}).listen(8000);
console.log(`Worker ${process.pid} started`);
}
ستشارك Node.js التي تعمل الآن المنفذ 8000 بين العمليات العاملة (workers):
$ node server.js
Master 3596 is running
Worker 4324 started
Worker 4520 started
Worker 6056 started
Worker 5644 started
انتبه رجاءً إلى أنَّه ليس بالإمكان إعداد أنبوب مسمى (named pipe) لخادم في عمليَّة عاملة في بيئة ويندوز.
كيفية العمل
تُولَّد العمليات العاملة باستعمال التابع child_process.fork()
، لذا بإمكان هذه العمليات التواصل مع العمليات الأب لها عبر قناة الاتصال IPC وتمرير معالجات الخادم ذهابًا وإيابًا.
تدعم وحدة العناقيد (cluster) أسلوبين لتوزيع الاتصالات الواردة؛ أولهما (ويعدُّ الاسلوب الافتراضي في جميع المنصات باستثناء ويندوز) يعتمد على التناوب (round-robin)، إذ تستمع العمليَّة الرئيسية (master process) إلى المنفذ، وتقبل الاتصالات الجديدة، ثمَّ تُوزِّعها بطريقة التناوب مع وجود بعض الذكاء المدمج لمنع التحميل الزائد لعمليَّة عاملة. أمَّا أسلوب التابع الثاني فيعتمد على إنشاء العمليَّة الرئيسية مقبس استماع ثمَّ إرساله إلى العمليَّة العاملة المعنيَّة؛ تقبل بعدئذٍ العمليَّة العاملة الاتصالات الواردة مباشرةً.
نظريًّا، يجب أن يعطي الأسلوب الثاني أداءً أفضل. أمَّا عمليًّا، وُجِد أنَّ أسلوب التوزيع يفقد توازنه نتيجة حدوث تقلبات في مُجَدوِل نظام التشغيل، إذ تمت مراقبة أحمال معيَّنة ولوحظ أنَّ 70% من جميع الاتصالات قد وُزِّعت على عمليتين فقط من أصل ثمان عمليات!
لمَّا كان التابع server.listen()
يُسنِد غالب العمل إلى العمليَّة الرئيسية، نتج لدينا ثلاثة حالات يختلف فيها سلوك عمليَّة Node.js الطبيعية عن سلوك العمليَّة العاملة في عنقود وهي:
server.listen({fd: 7})
: لمَّا كانت الرسائل تُمرَّر إلى العمليَّة الرئيسية، فسيكون واصف الملف 7 في العمليَّة الأب مستمعًا، وسيُمرَّر المعالج إلى العمليَّة العاملة بدلًا من الاستماع إلى تخمين العمليَّة العاملة حول موارد واصف الملف ذي الرقم 7 المحتملة.server.listen(handle)
: سيُسبِّب الاستماع إلى المعالجات بشكل صريح بجعل العمليَّة العاملة تستعمل المعامل المعطى بدلًا من التحدث إلى العمليَّة الرئيسية.server.listen(0)
: هذا سيجعل الخادم يستمع إلى منفذٍ عشوائيٍّ. مع ذلك، ستستلم كل عمليَّة عاملة في عنقود نفس المنفذ العشوائي في كل مرة يُستدعَى فيهاlisten(0)
. الخلاصة، يكون المنفذ عشوائيًّا في المرة الأولى فقط ويمكن بعدها تخمين المنفذ. لاستعمال منفذ فريد، يمكن توليد رقم المنفذ اعتمادًا على معرف (ID) العمليَّة العاملة في العنقود.
لا توفِّر Node.js التوجيه المنطقي (routing logic). بناءً على ذلك، من المهم تصميم تطبيقٍ لا يعتمد بشكل كبير على الكائنات التي تخزِّن بياناتها في الذاكرة من أجل بعض الأمور مثل الجلسات وتسجيل الدخول.
بما أنَّ العمليات العاملة هي عمليات منفصلة تمامًا، يمكن قتلها أو إعادة توليدها بناءً على حاجة التطبيق دون التأثير على أيَّة عمليَّة عاملة أخرى. يستمر الخادم بقبول الاتصالات طالما هنالك بعض عمليات عاملة ما زالت على قيد الحياة. إن لم يعد هنالك أيَّة عمليَّة عاملة تعمل، فستنهى الاتصالات الموجودة آنذاك وستُرفض أيُّة اتصالات جديدة. لا تدير Node.js عدد العمليات العاملة تلقائيًّا، إذ يُعدُّ هذا من مسؤوليات التطبيق ليدير مجمِّع العمليَّة العاملة بقدر ما يحتاج.
رغم أنَّ الهدف الرئيسي من الوحدة cluster
هو استعمالها في الشبكات إلا أنَّه يمكن استعمالها في حالات أخرى حيث تتطلب عمليات عاملة.
الصنف Worker
أضيف في الإصدار v0.7.0.
يحوي الكائن Worker
على جميع المعلومات والتوابع العامة المتعلقة بالعمليات العاملة (worker). في حالة عمليَّة رئيسية (master)، يمكن الحصول عليه باستعمال cluster.workers
. أمَّا في حالة عمليَّة عاملة (worker)، يمكن الحصول عليه باستعمال cluster.worker
.
الحدث 'disconnect'
أضيف في الإصدار v0.7.7.
يشبه هذا الحدثُ الحدثَ cluster.on('disconnect')
باستثناء أنَّه يمكن استعماله بشكل خاص مع الصنف Worker
.
cluster.fork().on('disconnect', () => {
// فُصِلَت العمليَّة العاملة الآن
});
الحدث 'error'
أضيف في الإصدار v0.7.3.
هذا الحدث مماثل تمامًا لذلك الذي يوفره التابع child_process.fork()
.
يمكن استدعاء process.on('error')
أحيانًا ضمن العمليَّة العاملة.
الحدث 'exit'
أضيف في الإصدار v0.11.2.
code
: <number> حالة الخروج إن تم الخروج من العمليَّة بشكل طبيعي.signal
: <string> اسم الإشارة التي تسبَّبت في قتل أو إنهاء العمليَّة، مثل الإشارة SIGHUP.
يشبه هذا الحدثُ الحدثَ cluster.on('exit')
باستثناء أنَّه يمكن استعماله بشكل خاص مع الصنف Worker
.
const worker = cluster.fork();
worker.on('exit', (code, signal) => {
if (signal) {
console.log(`worker was killed by signal: ${signal}`);
} else if (code !== 0) {
console.log(`worker exited with error code: ${code}`);
} else {
console.log('worker success!');
}
});
الحدث 'listening'
أضيف في الإصدار v0.7.0.
address
: <Object>
يشبه هذا الحدثُ الحدثَ cluster.on('exit')
باستثناء أنَّه يمكن استعماله بشكل خاص مع الصنف Worker
.
cluster.fork().on('listening', (address) => {
// العمليَّة العاملة تستمع الآن
});
لا يُطلق هذا الحدث ضمن العمليَّة العاملة.
الحدث 'message'
أضيف في الإصدار v0.7.0.
Message
: <Object>handle
: <undefined> | <Object>
هذا الحدث مشابهٌ للحدث 'message' الخاص بوحدة العناقيد (تجده في الأسفل) باستثناء أنَّه يمكن استعماله بشكل خاص مع الصنف Worker
.
يمكن استدعاء process.on('message')
أحيانًا ضمن العمليَّة العاملة.
انظر أيضًا الحدث 'message' في الكائن process
.
في المثال التالي، سننشئ عنقودًا يَعُدُ الطلبيات في العمليَّة الرئيسية باستعمال نظام الرسائل:
const cluster = require('cluster');
const http = require('http');
if (cluster.isMaster) {
// http الاستمرار في تعقب طلبيات
let numReqs = 0;
setInterval(() => {
console.log(`numReqs = ${numReqs}`);
}, 1000);
// عدُّ الطلبيات
function messageHandler(msg) {
if (msg.cmd && msg.cmd === 'notifyRequest') {
numReqs += 1;
}
}
// notifyRequest بدء العمليات العاملة والاستماع إلى الرسائل التي تحوي العبارة
const numCPUs = require('os').cpus().length;
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
for (const id in cluster.workers) {
cluster.workers[id].on('message', messageHandler);
}
} else {
// http تملك العمليات العاملة خادم
http.Server((req, res) => {
res.writeHead(200);
res.end('hello world\n');
// تنبيه العمليَّة الرئيسية حول الطلبية
process.send({ cmd: 'notifyRequest' });
}).listen(8000);
}
الحدث 'online'
أضيف في الإصدار v0.7.0.
يشبه هذا الحدثُ الحدثَ cluster.on('online')
باستثناء أنَّه يمكن استعماله بشكل خاص مع الصنف Worker
.
cluster.fork().on('online', () => {
// العمليَّة العاملة متصلة الآن
});
لا يُطلق هذا الحدث ضمن العمليَّة العاملة.
worker.disconnect()
الإصدار | التغييرات |
---|---|
v7.3.0 | أصبح هذا التابع يعيد مرجعًا إلى الكائن worker .
|
v0.0.7 | أضيف هذا التابع. |
- القيم المعادة: <cluster.Worker> مرجعٌ إلى الكائن
worker
.
إن استدعي هذا التابع ضمن عمليَّة عاملة، فستُغلَق جميع الخوادم، وستنتظر هذه الخوادم الحدث 'close'، ثمَّ ستُفصَل قناة الاتصال IPC.
أمَّا إن استدعي هذا التابع ضمن عمليَّة رئيسية، فسترسل رسالة داخلية إلى العمليَّة العاملة تطلب منها استدعاء .disconnect()
من تلقاء نفسها.
يتسبَّب هذا التابع أيضًا في ضبط الخاصية .exitedAfterDisconnect
.
انتبه إلى أنَّه لن تُقبَل الاتصالات الجديدة بعد إغلاق الخادم، وقد تقبل هذه الاتصالات عبر أيَّة عمليَّة عاملة مستمعة أخرى. أضف إلى ذلك أنَّ إغلاق جميع الاتصالات يسمح بإغلاق الخادم بشكل طبيعي. عندما لم يعد هنالك أيَّة اتصالات موجودة، ستُغلَق القناة IPC للعمليَّة العاملة مما يسمح بموت العمليَّة بأمان (ارجع إلى التابع server.close()
للمزيد من التفاصيل).
ينطبق كل ما سبق على اتصالات الخادم فقط، إذ لا تُغلِق العمليات العاملة اتصالات العميل تلقائيًّا ولا تنتظر عمليَّة قطع الاتصال إغلاق تلك الاتصالات قبل الخروج.
انتبه إلى وجود التابع process.disconnect()
في العمليَّة العاملة، إذ ليس هذا التابع هو التابع الذي نتحدث عنه بل هو التابع subprocess.disconnect()
.
لمَّا كانت اتصالات الخادم التي تدوم لفترة طويلة تمنع أحيانًا العمليات الأبناء من قطع الاتصال، فهذا قد يكون مفيدًا لإرسال رسالة تنبِّه التطبيق لاتخاذ إجراءٍ محدَّدٍ تُغلَق عبره تلك الاتصالات. يمكن أيضًا أن يكون ذلك مفيدًا لتطبيق مهلة زمنية محدَّدة، إذ يمكن قتل العمليَّة العاملة إن لم يُطلَق الحدث 'disconnect' بعد فترة زمنيَّة معيَّنة.
if (cluster.isMaster) {
const worker = cluster.fork();
let timeout;
worker.on('listening', (address) => {
worker.send('shutdown');
worker.disconnect();
timeout = setTimeout(() => {
worker.kill();
}, 2000);
});
worker.on('disconnect', () => {
clearTimeout(timeout);
});
} else if (cluster.isWorker) {
const net = require('net');
const server = net.createServer((socket) => {
// لن تنتهي الاتصالات مطلقًا
});
server.listen(8000);
process.on('message', (msg) => {
if (msg === 'shutdown') {
// بدء إغلاق أية اتصالات للخادم
}
});
}
الخاصية worker.exitedAfterDisconnect
أضيفت في الإصدار v6.0.0.
تُضبَط هذه الخاصية عند استدعاء التابع .kill()
أو التابع .disconnect()
، وتكون قيمتها قبل ذلك undefined
.
تساعد هذه الخاصية على التمييز بين الخروج الطوعي والخروج العَرَضي، إذ قد تتخذ العمليَّة الرئيسية قرارًا يتعلق بإعادة توليد العمليَّة أم لا بناءً على قيمة هذه الخاصية.
cluster.on('exit', (worker, code, signal) => {
if (worker.exitedAfterDisconnect === true) {
console.log('Oh, it was just voluntary – no need to worry');
}
});
// قتل العمليَّة العاملة
worker.kill();
الخاصية worker.id
أضيفت في الإصدار v0.8.0.
تمثِّل هذه الخاصية المعرِّف الفريد المعطى للعمليَّة العاملة. طالما كانت العمليَّة على قيد الحياة، تكون قيمة هذه الخاصية هي المفتاح الذي يشير إلى تلك العمليَّة في cluster.workers
.
worker.isConnected()
أضيف في الإصدار v0.11.14.
يعيد هذا التابع القيمة true إن كانت العمليَّة العاملة متصلةً مع العمليَّة الرئيسية لها عبر قناة الاتصال IPC، أو تعيد القيمة false
خلاف ذلك. تتصل العمليَّة العاملة مع العمليَّة الرئيسية لها بعد إنشائها، ويُقطع الاتصال بينهما بعد إطلاق الحدث 'disconnect'.
worker.isDead()
أضيف في الإصدار v0.11.14.
يعيد هذا التابع القيمة true
إن أُنهيَت العمليَّة العاملة (سواءً خرجت العمليَّة بطوعها أو أُرسلت إشارة تجبرها على التوقف). خلا ذلك، تعيد القيمة false
.
worker.kill([signal='SIGTERM'])
أضيف في الإصدار v0.9.12.
signal
: <string> اسم الإشارة المراد إرسالها إلى العمليَّة العاملة. القيمة الافتراضية هي: 'SIGTERM'.
يُستعمَل هذ التابع لقتل العمليَّة العاملة عند استدعائها هنالك. إن استدعي في العمليَّة الرئيسية، فسيُفعِّل ذلك عبر قطع اتصال worker.process
ثمَّ -متى ما قُطِع الاتصال- يرسل الإشارة signal
إلى العمليَّة العاملة لقتلها. أمَّا إن استدعي في العمليَّة العاملة نفسها، فسيقطع اتصال القناة أولًا ثمَّ يجبر العمليَّة على الخروج مع حال الخروج 0.
يتسبَّب هذا التابع أيضًا في ضبط الخاصية .exitedAfterDisconnect
.
يُعدُّ هذا التابع اسمًا بديلًا للتابع worker.destroy()
، إذ أُوجِد من أجل التوافقية الرجوعيَّة (backwards compatibility)
ملاحظة: في العمليَّة العاملة، يكون التابع process.kill()
هو المسؤول عن قتل العمليَّة وليس هذا التابع.
الخاصية worker.process
أضيفت في الإصدار v0.7.0.
- <ChildProcess>
تنشأ جميع العمليات العاملة باستعمال التابع child_process.fork()
ويُخزَّن الكائن المعاد بعد استدعائه في الخاصية .process
، وسيصبح المتغير العام process
متاحًا في العملية العاملة.
انظر أيضًا توثيق العمليات الأبناء للمزيد من التفاصيل.
انتبه أيضًا إلى أنَّ العمليات العاملة ستستدعي process.exit(0)
إن أطلق الحدث 'disconnect' مع الكائن process
وقيمة الخاصية .exitedAfterDisconnect
آنذاك هي false
. هذا يساعد على تجنب الخروج عند انقطاع الاتصال بشكل غير مقصود.
worker.send(message[, sendHandle][, callback])
الإصدار | التغييرات |
---|---|
v4.0.0 | أضيف المعامل callback .
|
v0.7.0 | أضيف هذا التابع. |
message
: <Object>sendHandle
: <Handle>callback
: <Function>- القيم المعادة: <boolean>
يرسل هذا التابع رسالةً إلى العمليَّة العاملة أو العمليَّة الرئيسية مع إمكانية إرسالة معالج أيضًا.
إن استدعي هذا التابع في عمليَّة رئيسية، فسيُرسل رسالةً إلى عمليَّة عاملة محدَّدة، ويكافي في هذه الحالة التابع ChildProcess.send()
.
أمَّا إن استدعي في العمليَّة العاملة، فسيرسل رسالةً إلى العمليَّة الرئيسية لها، ويكافئ في هذه الحالة التابع process.send()
.
يوضِّح المثال التالي كيفية إرجاع الرسائل المرسلة من العمليَّة الرئيسية إليها:
if (cluster.isMaster) {
const worker = cluster.fork();
worker.send('hi there');
} else if (cluster.isWorker) {
process.on('message', (msg) => {
process.send(msg);
});
}
الحدث 'exit'
أضيف في الإصدار v0.7.9.
worker
: <cluster.Worker>code
: <number> حالة الخروج إن تم الخروج بشكل طبيعي.signal
: <string> اسم الإشارة التي تسببت في قتل العمليَّة، مثل 'SIGHUP'.
يُطلَق الحدث 'exit' عندما تخرج أو تتوقف أي عمليَّة عاملة.
يمكن أن يُستعمَل هذا الحدث لإعادة تشغيل العمليَّة من جديد عبر استدعاء .fork()
مجدَّدًا.
cluster.on('exit', (worker, code, signal) => {
console.log('worker %d died (%s). restarting...',
worker.process.pid, signal || code);
cluster.fork();
});
انظر أيضًا قسم «الحدث 'exit'» في توثيق العمليات الأبناء.
الحدث 'fork'
أضيف في الإصدار v0.7.0.
worker
: <cluster.Worker>
يُطلَق الحدث 'fork' عندما تتفرَّع عمليَّة عاملة جديدة. يمكن الاستفادة من هذا الحدث في مراقبة نشاط عميلة عاملة معيَّنة أو تحديد مهلة زمنيَّة مخصصة لها.
const timeouts = [];
function errorMsg() {
console.error('Something must be wrong with the connection ...');
}
cluster.on('fork', (worker) => {
timeouts[worker.id] = setTimeout(errorMsg, 2000);
});
cluster.on('listening', (worker, address) => {
clearTimeout(timeouts[worker.id]);
});
cluster.on('exit', (worker, code, signal) => {
clearTimeout(timeouts[worker.id]);
errorMsg();
});
الحدث 'listening'
أضيف في الإصدار v0.7.0.
worker
: <cluster.Worker>address
: <Object>
يُطلَق الحدث 'listening' في الخادم بعد استدعاء listen()
من عمليَّة عاملة، ويُطلَق أيضًا في cluster
في العمليَّة الرئيسية.
يُنفَّذ معالج هذا الحدث مع وسيطين؛ الأول هو worker
الذي يحتوي على الكائن worker
، والثاني هو address
الذي يحتوي على خاصِّيَّات الاتصال address
، و port
، و addressType
. هذا مفيد جدًا عندما تستمع العمليَّة العاملة إلى أكثر من عنوان واحد.
cluster.on('listening', (worker, address) => {
console.log(
`A worker is now connected to ${address.address}:${address.port}`);
});
يأخذ المعامل addressType
إحدى القيم التالية:
- 4: تشير إلى TCPv4، أو
- 6: تشير إلى TCPv6، أو
- -1: تشير إلى مقبس نطاق يونكس (unix domain socket)، أو
- 'udp4' أو 'udp6': تشير إلى UDPv4 أو UDPv6 على التوالي.
الحدث 'message'
الإصدار | التغييرات |
---|---|
v6.0.0 | أصبح بالإمكان تمرير المعامل worker الآن.
|
v2.5.0 | أضيف هذا الحدث. |
worker
: <cluster.Worker>message
: <Object>handle
: <undefined> | <Object>
يُطلَق هذا الحدث عندما يستلم العنقود الرئيسي رسالةً من أي عمليَّة عاملة.
انظر أيضًا الحدث 'message' في توثيق العمليات الأبناء.
ملاحظة: قبل الإصدار Node.js v6.0، كان هذا الحدث يُطلِق المعامل message
والمعامل handle
فقط دون المعامل worker
أي عكس ما كان مذكورًا في التوثيق.
يُطلَب استعمال الإصدارات الأحدث دومًا إن كانت مدعومة. مع ذلك، يمكن الاستغناء عن الكائن worker
، إذ من الممكن التغلب على هذا التناقض عبر التحقُّق من عدد المعاملات بالشكل التالي:
cluster.on('message', (worker, message, handle) => {
if (arguments.length === 2) {
handle = message;
message = worker;
worker = undefined;
}
// ...
});
الحدث 'online'
أضيف في الإصدار v0.7.0.
worker
: <cluster.Worker>
يجب على العمليَّة العاملة الجديدة أن ترسل رسالة إلى العمليَّة الرئيسية تخبره بأنَّها أصبحت متصلة. عندما تستلم العمليَّة الرئيسية هذه الرسالة، يُطلَق هذا الحدث. الفارق بين الحدث 'fork' والحدث 'online' هو أنَّ الأول يُطلَق عندما تنشئ العمليَّة الرئيسية عمليَّة عاملة، والثاني يطلق عندما تبدأ العمليَّة العاملة في العمل.
cluster.on('online', (worker) => {
console.log('Yay, the worker responded after it was forked');
});
الحدث 'setup'
أضيف في الإصدار v0.7.1.
settings
: <Object>
يُطلَق هذا الحدث في كل مرة يُستدعَى فيها التابع .setupMaster()
.
يصبح الكائن settings
هو الكائن cluster.settings
نفسه في الوقت الذي يستدعى فيه التابع .setupMaster()
وهو توجيهي (advisory) فقط، إذ من الممكن استدعاء .setupMaster()
عدَّة مرات بضغطة بسيطة.
إن كانت الدقة مهمة جدًا، فاستعمل الكائن cluster.settings
.
cluster.disconnect([callback])
أضيف في الإصدار v0.7.7.
callback
: <Function> دالةٌ تستدعى عندما تصبح جميع العمليات العاملة غير متصلة وتغلق جميع المعالجات.
يستدعى التابع .disconnect()
مع كل عمليَّة عاملة في cluster.workers
. عندما تصبح تلك العمليات غير متصلة وتغلق جميع معالجات الأحداث، سيؤدي ذلك إلى موت العمليَّة الرئيسية بأمان إن لم يكن هنالك أيَّة أحداث منتظرة.
يمكن تمرير دالة رد نداء إلى هذا التابع اختياريًّا لاستدعائها عند الانتهاء.
لا يمكن استدعاء هذا التابع إلا مع عمليَّة رئيسية.
cluster.fork([env])
أضيف في الإصدار v0.6.0.
env
: <Object> زوجٌ من مفتاح/قيمة يراد إضافته إلى بيئة العمليَّة العاملة.- القيم المعادة: <cluster.Worker>
يولِّد هذا التابع عمليَّة عاملة جديدة.
لا يمكن استدعاء هذا التابع إلا من العمليَّة الرئيسية.
الخاصية cluster.isMaster
أضيف في الإصدار v0.8.1.
تحدِّد هذه الخاصية إن كانت العمليَّة عمليَّةً رئيسيةً باستعمال process.env.NODE_UNIQUE_ID
، إذ تكون قيمة هذه الخاصية true
إن كانت قيمة process.env.NODE_UNIQUE_ID
هي undefined
.
الخلاصة، تكون قيمة هذه الخاصية true إن كانت العمليَّة عمليَّةً رئيسية.
الخاصية cluster.isWorker
أضيفت في الإصدار v0.6.0.
تحدِّد هذه الخاصية إن كانت العمليَّة عمليَّةً عاملة، إذ تكون قيمتها true
إن لم تكن العمليَّة عمليَّةً رئيسية (هي عكس الخاصية cluster.isMaster
تمامًا).
الخاصية cluster.schedulingPolicy
أضيفت في الإصدار v0.11.2.
تمثِّل هذه الخاصية أسلوب الجدولة، إذ إمَّا أن تكون قيمتها cluster.SCHED_RR
من أجل أسلوب التناوب (round-robin) أو cluster.SCHED_NONE
لترك الأمر إلى نظام التشغيل. هذه الخاصية هي خاصية عامة وتكون غير فعالة ولا يمكن ضبطها متى ما ولدت أول عمليَّة عاملة أو متى ما استدعي التابع cluster.setupMaster()
أيهما يحدث أولًا.
القيمة الافتراضيَّة لهذه الخاصية هي SCHED_RR
على جميع المنصات باستثناء ويندوز. سيغيِّر ويندوز قيمة هذه الخاصية إلى SCHED_RR
متى ما توافرت المكتبة libuv لنشر المعالجات IOCP بكفاءة دون استهلاك قدر كبير من الأداء.
يمكن ضبط الخاصية cluster.schedulingPolicy
عبر متغير البيئة NODE_CLUSTER_SCHED_POLICY
، إذ يمكن استعمال إحدى القيمتين: 'rr' أو 'none'.
الخاصية cluster.settings
الإصدار | التغييرات |
---|---|
v9.5.0 | إضافة الخيار cwd .
|
v9.4.0 | إضافة الخيار windowsHide .
|
v8.2.0 | إضافة الخيار inspectPort .
|
v6.4.0 | إضافة الخيار stdio .
|
v0.7.1 | إضافة هذه الخاصية. |
options
: <Object> كائنٌ يمكن أن يحتوي على الخيارات التالية:execArgv
: <string[]> قائمة سلاسل نصية تمثِّل الوسائط المراد تمريرها إلى عمليَّة Node.js القابلة للتنفيذ. القيمة الافتراضيَّة هي:process.execArgv
.exec
: <string> المسار الذي يشير إلى ملف العمليَّة العاملة. القيمة الافتراضية هي:process.argv[1]
.args
: <string[]> قائمةٌ من سلاسل نصية تمثِّل الوسائط المراد تمريرها إلى العمليَّة العاملة. القيمة الافتراضية هي:process.argv.slice(2)
.cwd
: <string> سلسلةٌ نصيةٌ تمثِّل مجلد العمل الحالي للعمليَّة العاملة. القيمة الافتراضيَّة هي:undefined
(تورث من العمليَّة الأب).silent
: <boolean> قيمة منطقيَّة تحدِّد إن كان يراد إسال المخرجات إلى مجرى الخرج القياسي للعمليَّة الأب أم لا. القيمة الافتراضية هي:false
.stdio
: <Array> ضبط مجاري الخرج والدخل القياسية للعمليَّة الفرعية. لمَّا كانت الوحدةcluster
تعتمد على القناة IPC، فيجب أن يحوي هذا الضبط على 'ipc'. عندما يعطى هذا الضبط، يُتجاهل الضبطsilent
.uid
: <number> عددٌ يحدِّد مُعرِّف المستخدم المالك للعمليَّة (ارجع إلىsetuid(2)
).gid
: <number> عددٌ يحدِّد مُعرِّف المجموعة المالكة للعمليَّة (ارجع إلىsetgid(2)
).inspectPort
: <number> | <Function> يعين منفذ مراقب للعمليَّة العاملة. يمكن أن يكون هذا الضبط عددًا أو دالةً تعيد عددًا دون أن يُمرَّر إليها أي وسيط. افتراضيًّا، يكون لكل عمليَّة عاملة منفذًا خاصًّا بها يتزايد بدءًا من المنفذprocess.debugPort
الخاص بالعمليَّة الرئيسية.windowsHide
: <boolean> قيمةٌ منطقيةٌ تتحكم بإظهار وإخفاء نافذة الطرفية للعمليَّة الفرعية التي ستُنشأ دومًا بشكل اعتيادي في أنظمة ويندوز. القيمة الافتراضيَّة هي:false
.
سيحتوي الكائن settings
على الإعدادات بعد استدعاء التابع .setupMaster()
(أو التابع .fork()
) من ضمنها الإعدادات الافتراضية.
لا يفترض تغيير هذا الكائن أو ضبطه يدويًّا.
cluster.setupMaster([settings])
الإصدار | التغييرات |
---|---|
v6.4.0 | أضيف الخيار stdio .
|
v0.7.1 | أضيف هذا التابع. |
settings
: <Object> ارجع إلى الخاصيةcluster.settings
.
يستعمل هذا التابع لتغيير سلوك 'fork' الافتراضي، إذ ستصبح الإعدادات المضبوطة في الخاصية cluster.settings
هي الإعدادات الحاليَّة متى ما استدعي.
يرجى الانتباه إلى النقاط التالية:
- ستصبح التغييرات الحاصلة سارية المفعول مع الاستدعاءات اللاحقة للتابع
.fork()
فقط ولن تؤثر مطلقًا على العمليات العاملة التي تعمل مسبقًا. - الخاصية الوحيدة التي لا يمكن للعمليَّة العاملة عبر
.setupMaster()
هيenv
المُمرَّرة إلى التابع.fork()
. - تطبق الإعدادات الافتراضيَّة المذكورة في الأعلى عند استدعاء التابع
.setupMaster()
لأول مرة فقط، ثمَّ تصبح الاعدادات الافتراضية للاستدعاءات اللاحقة هي القيم الحالية المضبوطة في الوقت الذي يستدعى التابع .setupMaster()
فيه.
تفحَّص المثال التالي:
const cluster = require('cluster');
cluster.setupMaster({
exec: 'worker.js',
args: ['--use', 'https'],
silent: true
});
cluster.fork(); // عاملة http عمليَّة
cluster.setupMaster({
exec: 'worker.js',
args: ['--use', 'http']
});
cluster.fork(); // عاملة http عمليَّة
لا يمكن تنفيذ هذه الشيفرة إلا من عمليَّة رئيسية.
الخاصية cluster.worker
أضيفت في الإصدار v0.7.0.
تمثل هذه الخاصية مرجعًا إلى الكائن worker
الحالي، وهي غير متاحة في العمليَّة الرئيسية.
const cluster = require('cluster');
if (cluster.isMaster) {
console.log('I am master');
cluster.fork();
cluster.fork();
} else if (cluster.isWorker) {
console.log(`I am worker #${cluster.worker.id}`);
}
الخاصية cluster.workers
أضيفت في الإصدار v0.7.0.
تُخزِّن هذه الخاصية الكائنات worker
الفعالة آنذاك، إذ يربط كل كائن مع معرِّف id
. يمكن الاستفادة من هذه الخاصية بتطبيق حلقة تكراريَّة على جميع العمليات العاملة، وهي متاحةٌ فقط في العمليَّة الرئيسية.
تزال العمليَّة العاملة من cluster.workers
بعد أن تصبح غير متصلة ثمَّ تخرج، ولا يمكن أن يحدَّد ترتيب وقوع هذين الحدثين (الحدث 'disconnected' والحدث 'exit') مسبقًا. مع ذلك، يُضمن بإزالة العمليَّة العاملة من القائمة cluster.workers
قبل إطلاق آخر الحدثين 'disconnected' و 'exit'.
// تطبيق حلقة تكرارية لفعل شيء مع جميع العمليات العاملة
function eachWorker(callback) {
for (const id in cluster.workers) {
callback(cluster.workers[id]);
}
}
eachWorker((worker) => {
worker.send('big announcement to all workers');
});
استعمال مُعرِّف العمليَّة العاملة الفريد هو أسهل طريقة لتحديد هذه العمليَّة.
socket.on('data', (id) => {
const worker = cluster.workers[id];
});