服务异常邮件通知

这里使用swiftMail作为邮件类

  1. composer require swiftmailer/swiftmailer

在config配置文件下新建param.php,配置邮件相关信息

  1. <?php
  2. return [
  3. #swift mail
  4. 'swift.mail.host' => 'smtp.exmail.qq.com',
  5. 'swift.mail.port' => 25,
  6. 'swift.mail.username' => 'xxx@xxx.com',
  7. 'swift.mail.password' => 'xxx',
  8. 'swift.mail.to' => ['xxx@xxx.com', 'aa@aaa.com'],
  9. ];

编写监听KernalEvent::SERVICE_FAIL事件

在config/dev/listener.php中加入如下配置

  1. <?php
  2. return [
  3. 'services' => [
  4. [
  5. 'eventName' => 'kernal.service_fail',
  6. 'listener' => 'src\Common\Listeners\ServiceFailListener',
  7. 'priority' => 10,
  8. ],
  9. ]
  10. ];

编写src\Common\Listeners\ServiceFailListener类

我们使用redis任务队列进行异常服务的统计,并启一个子进程进行消费。

  1. <?php
  2. namespace src\Common\Listeners;
  3. use AsyncRedis;
  4. class ServiceFailListener extends \Listener
  5. {
  6. public function setMethod()
  7. {
  8. return 'onServiceFail';
  9. }
  10. /**
  11. * 服务调用失败事件
  12. * @param \Event
  13. */
  14. public function onServiceFail(\Event $event)
  15. {
  16. //当服务调用失败时,你可以做上报监控平台,邮件通知等等业务。请以异步方式上报
  17. $data = $event->getProperty();
  18. //无可用的服务
  19. yield AsyncRedis::rPush('service_fail', json_encode([
  20. 'service' => $data['service'],
  21. 'cmd' => $data['cmd'],
  22. 'ip' => $data['ip'],
  23. 'port' => $data['port'],
  24. ]));
  25. yield;
  26. }
  27. }

配置config/dev/app.php中的process选项

  1. 'process' => [
  2. 'src\Common\Process\ServiceFailProcess',
  3. ],

实现src\Common\Process\ServiceFailProcess消费队列,发送邮件

  1. <?php
  2. namespace src\Common\Process;
  3. use Group\Process;
  4. use Redis;
  5. use swoole_process;
  6. use Group\Config\Config;
  7. class ServiceFailProcess extends Process
  8. {
  9. public function register()
  10. {
  11. $config = Config::get("database::redis");
  12. $config = $config['default'];
  13. $redis = new Redis;
  14. $redis->connect($config['host'], $config['port']);
  15. if (isset($config['auth'])) {
  16. $redis->auth($config['auth']);
  17. }
  18. $redis->setOption(Redis::OPT_PREFIX, isset($config['prefix']) ? $config['prefix'] : '');
  19. $process = new swoole_process(function($process) use ($redis) {
  20. //轮询
  21. swoole_timer_tick(1000, function() use ($redis) {
  22. $errors = $redis->lPop('service_fail');
  23. if ($errors) {
  24. $errors = json_decode($errors, true);
  25. //发送邮件
  26. if (is_array($errors['cmd'])) {
  27. $cmd = implode(",", $errors['cmd']);
  28. } else {
  29. $cmd = $errors['cmd'];
  30. }
  31. $email = new Email;
  32. if ($errors['ip'] == "" || $errors['port'] == "") {
  33. $email->sendEmail("【服务调用失败】".$errors['service']."服务", "没有一个可用的服务。调用命令:".$cmd);
  34. } else {
  35. $email->sendEmail("【服务调用失败】".$errors['service']."服务", "服务地址: ".$errors['ip'].":".$errors['port']."。调用命令:".$cmd);
  36. }
  37. unset($email);
  38. }
  39. });
  40. });
  41. return $process;
  42. }
  43. }
  44. class Email
  45. {
  46. public function sendEmail($title, $body, $format = 'text')
  47. {
  48. $to = Config::get("param::swift.mail.to");
  49. $host = Config::get("param::swift.mail.host");
  50. $port = Config::get("param::swift.mail.port");
  51. $username = Config::get("param::swift.mail.username");
  52. $password = Config::get("param::swift.mail.password");
  53. if ($format == "html") {
  54. $format = 'text/html';
  55. } else {
  56. $format = 'text/plain';
  57. }
  58. $transport = \Swift_SmtpTransport::newInstance($host, $port)
  59. ->setUsername($username)
  60. ->setPassword($password);
  61. $mailer = \Swift_Mailer::newInstance($transport);
  62. $email = \Swift_Message::newInstance();
  63. $email->setSubject($title);
  64. $email->setFrom(array($username => 'clothesmake'));
  65. $email->setTo($to);
  66. if ($format == 'text/html') {
  67. $email->setBody($body, 'text/html');
  68. } else {
  69. $email->setBody($body);
  70. }
  71. $res = $mailer->send($email);
  72. if ($res == 1) {
  73. return true;
  74. }
  75. return false;
  76. }
  77. }

重启主服务即可~