RabbitmqConsumerController.php 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. <?php
  2. namespace console\controllers;
  3. use yii\console\Controller;
  4. use yii\console\ExitCode;
  5. use Yii;
  6. /**
  7. * RabbitMQ 消费者控制器
  8. *
  9. * 用途: 运行 RabbitMQ 队列消费者,持续监听并处理消息
  10. *
  11. * 用法示例:
  12. * ./yii rabbitmq-consumer/custom - 运行客户操作消费者
  13. * ./yii rabbitmq-consumer/stock - 运行库存管理消费者
  14. * ./yii rabbitmq-consumer/notify - 运行消息通知消费者
  15. * ./yii rabbitmq-consumer/all - 运行所有消费者(需要多个终端或后台进程)
  16. * ./yii rabbitmq-consumer/status - 查看消费者状态
  17. *
  18. * 使用 supervisor 管理进程示例:
  19. * 配置文件位置: /etc/supervisor/conf.d/rabbitmq.conf
  20. */
  21. class RabbitmqConsumerController extends Controller
  22. {
  23. /**
  24. * 超时时间(秒),0 表示不超时
  25. */
  26. public $timeout = 0;
  27. /**
  28. * 获取命令描述
  29. */
  30. public function getHelp()
  31. {
  32. return <<<EOT
  33. RabbitMQ 消费者管理命令
  34. 使用方法:
  35. ./yii rabbitmq-consumer/custom 运行客户操作消费者
  36. ./yii rabbitmq-consumer/stock 运行库存管理消费者
  37. ./yii rabbitmq-consumer/notify 运行消息通知消费者
  38. ./yii rabbitmq-consumer/all 运行所有消费者(开发环境使用)
  39. ./yii rabbitmq-consumer/status 查看消费者状态
  40. 选项:
  41. --timeout=N 设置消费超时时间(秒),默认不超时
  42. 示例:
  43. ./yii rabbitmq-consumer/custom --timeout=3600
  44. ./yii rabbitmq-consumer/stock
  45. ./yii rabbitmq-consumer/notify
  46. 生产环境部署:
  47. 建议使用 supervisor 或其他进程管理工具管理消费者进程,
  48. 参考 supervisor 配置文件示例。
  49. EOT;
  50. }
  51. /**
  52. * 获取命令选项
  53. */
  54. public function options($actionID)
  55. {
  56. return ['timeout'];
  57. }
  58. /**
  59. * 运行客户操作消费者
  60. * 处理: 创建客户、更新客户、删除客户等业务操作
  61. *
  62. * @return int 退出码
  63. */
  64. public function actionCustom()
  65. {
  66. return $this->runConsumer('customConsumer', 'customQueue', 'custom');
  67. }
  68. /**
  69. * 运行库存管理消费者
  70. * 处理: 库存增加、库存扣减、库存调整等业务操作
  71. *
  72. * @return int 退出码
  73. */
  74. public function actionStock()
  75. {
  76. return $this->runConsumer('stockConsumer', 'stockQueue', 'stock');
  77. }
  78. /**
  79. * 运行消息通知消费者
  80. * 处理: 新订单、新客户、充值、销账、配送状态等通知
  81. *
  82. * @return int 退出码
  83. */
  84. public function actionNotify()
  85. {
  86. return $this->runConsumer('notifyConsumer', 'notifyQueue', 'notify');
  87. }
  88. /**
  89. * 运行所有消费者(开发环境或测试环境使用)
  90. *
  91. * 注意: 生产环境建议为每个消费者启动独立进程
  92. *
  93. * @return int 退出码
  94. */
  95. public function actionAll()
  96. {
  97. $this->stdout("启动所有 RabbitMQ 消费者\n");
  98. $this->stdout("提示: 建议使用 supervisor 管理多个消费者进程\n\n");
  99. $consumers = [
  100. ['name' => 'customConsumer', 'queue' => 'customQueue', 'type' => 'custom'],
  101. ['name' => 'stockConsumer', 'queue' => 'stockQueue', 'type' => 'stock'],
  102. ['name' => 'notifyConsumer', 'queue' => 'notifyQueue', 'type' => 'notify'],
  103. ];
  104. foreach ($consumers as $consumer) {
  105. $this->stdout("启动消费者: {$consumer['name']}\n");
  106. $this->runConsumer($consumer['name'], $consumer['queue'], $consumer['type']);
  107. }
  108. return ExitCode::OK;
  109. }
  110. /**
  111. * 查看消费者状态
  112. *
  113. * @return int 退出码
  114. */
  115. public function actionStatus()
  116. {
  117. $this->stdout("RabbitMQ 消费者状态\n");
  118. $this->stdout(str_repeat('=', 50) . "\n");
  119. try {
  120. // 获取 RabbitMQ 配置
  121. $rabbitmqConfig = require(Yii::getAlias('@common/config/rabbitMQ.php'));
  122. // 显示消费者信息
  123. if (isset($rabbitmqConfig['consumers'])) {
  124. $this->stdout("\n已配置的消费者:\n");
  125. foreach ($rabbitmqConfig['consumers'] as $index => $consumer) {
  126. $name = $consumer['name'] ?? 'unknown';
  127. $callbacks = $consumer['callbacks'] ?? [];
  128. $queueNames = array_keys($callbacks);
  129. $this->stdout(" [{$index}] 消费者名称: {$name}\n");
  130. foreach ($queueNames as $queueName) {
  131. $this->stdout(" └─ 队列: {$queueName}\n");
  132. }
  133. }
  134. }
  135. // 显示队列信息
  136. if (isset($rabbitmqConfig['queues'])) {
  137. $this->stdout("\n已配置的队列:\n");
  138. foreach ($rabbitmqConfig['queues'] as $index => $queue) {
  139. $name = $queue['name'] ?? 'unknown';
  140. $durable = $queue['durable'] ?? false ? '✓' : '✗';
  141. $this->stdout(" [{$index}] 队列名称: {$name} (持久化: {$durable})\n");
  142. }
  143. }
  144. $this->stdout("\n" . str_repeat('=', 50) . "\n");
  145. $this->stdout("提示: 使用 'rabbitmqctl list_consumers' 查看 RabbitMQ 中的实时消费者\n");
  146. return ExitCode::OK;
  147. } catch (\Exception $e) {
  148. $this->stderr("错误: " . $e->getMessage() . "\n");
  149. return ExitCode::UNSPECIFIED_ERROR;
  150. }
  151. }
  152. /**
  153. * 运行消费者的核心方法
  154. *
  155. * @param string $consumerName 消费者名称
  156. * @param string $queueName 队列名称
  157. * @param string $type 消费者类型(用于日志区分)
  158. * @return int 退出码
  159. */
  160. private function runConsumer($consumerName, $queueName, $type)
  161. {
  162. try {
  163. $this->stdout("启动 {$type} 消费者: {$consumerName}\n");
  164. $this->stdout("监听队列: {$queueName}\n");
  165. $this->stdout("按 Ctrl+C 停止消费者\n\n");
  166. // 获取消费者实例
  167. $consumer = Yii::$app->rabbitmq->getConsumer($consumerName);
  168. if (!$consumer) {
  169. $this->stderr("错误: 无法获取消费者 '{$consumerName}'\n");
  170. return ExitCode::CONFIG;
  171. }
  172. // 运行消费者(阻塞式)
  173. Yii::info("Consumer started: {$consumerName} on queue: {$queueName}", "rabbitmq.{$type}");
  174. $consumer->consume();
  175. return ExitCode::OK;
  176. } catch (\Exception $e) {
  177. $this->stderr("消费者异常: " . $e->getMessage() . "\n");
  178. Yii::error("Consumer exception: " . $e->getMessage(), "rabbitmq.{$type}");
  179. return ExitCode::UNSPECIFIED_ERROR;
  180. }
  181. }
  182. }