messenger.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. 'use strict';
  2. const cluster = require('cluster');
  3. const sendmessage = require('sendmessage');
  4. const debug = require('debug')('egg-cluster:messenger');
  5. /**
  6. * master messenger,provide communication between parent, master, agent and app.
  7. *
  8. * ┌────────┐
  9. * │ parent │
  10. * /└────────┘\
  11. * / | \
  12. * / ┌────────┐ \
  13. * / │ master │ \
  14. * / └────────┘ \
  15. * / / \ \
  16. * ┌───────┐ ┌───────┐
  17. * │ agent │ ------- │ app │
  18. * └───────┘ └───────┘
  19. *
  20. *
  21. * in app worker
  22. *
  23. * ```js
  24. * process.send({
  25. * action: 'xxx',
  26. * data: '',
  27. * to: 'agent/master/parent', // default to app
  28. * });
  29. * ```
  30. *
  31. * in agent worker
  32. *
  33. * ```js
  34. * process.send({
  35. * action: 'xxx',
  36. * data: '',
  37. * to: 'app/master/parent', // default to agent
  38. * });
  39. * ```
  40. *
  41. * in parent
  42. *
  43. * ```js
  44. * process.send({
  45. * action: 'xxx',
  46. * data: '',
  47. * to: 'app/agent/master', // default to be ignore
  48. * });
  49. * ```
  50. */
  51. class Messenger {
  52. constructor(master) {
  53. this.master = master;
  54. this.hasParent = !!process.send;
  55. process.on('message', msg => {
  56. msg.from = 'parent';
  57. this.send(msg);
  58. });
  59. process.once('disconnect', () => {
  60. this.hasParent = false;
  61. });
  62. }
  63. /**
  64. * send message
  65. * @param {Object} data message body
  66. * - {String} from from who
  67. * - {String} to to who
  68. */
  69. send(data) {
  70. if (!data.from) {
  71. data.from = 'master';
  72. }
  73. // recognise receiverPid is to who
  74. if (data.receiverPid) {
  75. if (data.receiverPid === String(process.pid)) {
  76. data.to = 'master';
  77. } else if (data.receiverPid === String(this.master.agentWorker.pid)) {
  78. data.to = 'agent';
  79. } else {
  80. data.to = 'app';
  81. }
  82. }
  83. // default from -> to rules
  84. if (!data.to) {
  85. if (data.from === 'agent') data.to = 'app';
  86. if (data.from === 'app') data.to = 'agent';
  87. if (data.from === 'parent') data.to = 'master';
  88. }
  89. // app -> master
  90. // agent -> master
  91. if (data.to === 'master') {
  92. debug('%s -> master, data: %j', data.from, data);
  93. // app/agent to master
  94. this.sendToMaster(data);
  95. return;
  96. }
  97. // master -> parent
  98. // app -> parent
  99. // agent -> parent
  100. if (data.to === 'parent') {
  101. debug('%s -> parent, data: %j', data.from, data);
  102. this.sendToParent(data);
  103. return;
  104. }
  105. // parent -> master -> app
  106. // agent -> master -> app
  107. if (data.to === 'app') {
  108. debug('%s -> %s, data: %j', data.from, data.to, data);
  109. this.sendToAppWorker(data);
  110. return;
  111. }
  112. // parent -> master -> agent
  113. // app -> master -> agent,可能不指定 to
  114. if (data.to === 'agent') {
  115. debug('%s -> %s, data: %j', data.from, data.to, data);
  116. this.sendToAgentWorker(data);
  117. return;
  118. }
  119. }
  120. /**
  121. * send message to master self
  122. * @param {Object} data message body
  123. */
  124. sendToMaster(data) {
  125. this.master.emit(data.action, data.data);
  126. }
  127. /**
  128. * send message to parent process
  129. * @param {Object} data message body
  130. */
  131. sendToParent(data) {
  132. if (!this.hasParent) {
  133. return;
  134. }
  135. process.send(data);
  136. }
  137. /**
  138. * send message to app worker
  139. * @param {Object} data message body
  140. */
  141. sendToAppWorker(data) {
  142. for (const id in cluster.workers) {
  143. const worker = cluster.workers[id];
  144. if (worker.state === 'disconnected') {
  145. continue;
  146. }
  147. // check receiverPid
  148. if (data.receiverPid && data.receiverPid !== String(worker.process.pid)) {
  149. continue;
  150. }
  151. sendmessage(worker, data);
  152. }
  153. }
  154. /**
  155. * send message to agent worker
  156. * @param {Object} data message body
  157. */
  158. sendToAgentWorker(data) {
  159. if (this.master.agentWorker) {
  160. sendmessage(this.master.agentWorker, data);
  161. }
  162. }
  163. }
  164. module.exports = Messenger;