业务背景:
公司自己做的oa系统,不同的模块需要用不同的邮箱发送信息给收件人。比如:员工离职的时候用离职的邮箱发送离职邮件通知,员工入职的时候用入职的邮箱发送入职邮件通知。发邮件是一件耗时的任务,如果用同步执行的话会影响用户体验,就想到能不能把发邮件的操作放到队列中来进行。后来发现laravel其实是做不到的。
瓶颈:
我们用的是laravel框架,经过踩坑发现其实laravel并不支持我们上述的业务需求。大家可以参照一下这个url:https://learnku.com/laravel/t/3285/resolved-how-to-make-laravel-53-support-multiple-mail-driver-and-can-switch-in-operation
解决问题的思路:
使用队列来保证异步,在出队的时候获取请求数据,更新账号发送邮件,来保证使用的是不同邮箱。
那有的人可能就会问了:你怎么能保证使用异步的同时又能够用不同的账号发送邮件呢?有两点:
(1)我试过,而且成功了。
(2)这个时候就需要论证一下了。首先这样做是一定能保证异步的,这一点想必大家都没疑问。那有疑问的应该就是,如何能保证用不同的账号发送邮件呢?我们这样想:队列在出队后,执行一个laravel相关的脚本,在执行脚本的过程中,我们可以理解为又新起了一个进程,这个进程有自己的容器,那么我们就可以为这个进程设置它自己的邮件账号。这样理解应该就没有什么问题了。下图是artisan命令的介绍,来论述我自己的理论。
实现方法:
(1)数据放到redis中,使用key存储起来
为啥这样做?试想一下,你在传参的过程中,如果传的是个数组,你是不是要把它给json_encode一下?因为command命令是不支持直接传数组的,只能传字符串。用json字符串做参数你要考虑的有一下几点:你的command的命令能写对吗?你传的字符串的格式能写对吗?laravel在执行你的command命令的时候会不会对你的json字符串做一下处理,导致结果错误?你在decode的时候能不能得到想要的结果?我试了几种方法,没成功,还是乖乖的用了redis。
$this->msg = serialize($this->msg); $key = $this->from .'_' . (microtime(true) * 1000); Redis::set($key, $this->msg); Redis::expire($key, 60 * 10); $command = 'php artisan email:send --msgKey='. $key . ' --from=' . $this->from; shell_exec($command);
(2)出队执行发送邮件操作
$this->info('start'); $msgKey= $this->option('msgKey'); $from = $this->option('from'); if (empty($msgKey) || empty($from)) { return []; } $msg = Redis::get($msgKey); if (empty($msg)) { return []; } $msg = unserialize($msg); Log::info('EmailSendMes', [$msg, $from]); MailHelper::sendMail($msg, $from); $this->info('end');
(3)设置发送邮件的邮箱
感悟:
今天下午在公司门口走了走,阳光已经不是很烈了,能闻到草和泥土的味道。不知名的花在悠闲的开着,白鹭在水面上自由的飞、叫、盘旋。海风吹来,整个人都感觉很舒服,很幸福。这样的日子好久没有过了。想想自己,从高中,到大学,到毕业,一直都在奔波,都在与别人竞争,与自己竞争,像这样生活已经很久没有过了。你就感觉很舒服,很安心,很踏实。不会再去想,人活着的意义,人奋斗的意义,因为那一刻的美好,就是一切的答案。趁年轻,想做的事,赶紧吧,不要给自己留遗憾。