项目从 laravel 5.2 迁移到 5.7,发现之前的 Mail 有点问题,今天重构了下,用到几个地方:
参考文档:
https://laravelacademy.org/post/9569.html
用到的几个技术点:
app/Mail/Offer.php - 可邮件类
resources/views/emails/offer.blade.php - email 模板
app/Providers/EventServiceProvider.php - 注册邮件事件
app/Listeners/LogSentMessage.php - 邮件发送成功回调
看了点源码,感觉绕的有点麻烦,不过架构应该清晰吧。。。。
同事一直想在项目中使用队列,这个问题我也纠结了好久了,干脆就趁这次,整下队列,下面记录下过程:
参考文档:
https://laravelacademy.org/post/9574.html
需要的 2 个额外的技术:
supervisor
horizon
1.supervisor
参考文章:
http://supervisord.org/
http://liyangliang.me/posts/2015/06/using-supervisor/
http://blog.51cto.com/lixcto/1539136
https://www.load-page.com/manuals/web-server/chapter-tools/supervisor.html
https://www.cnblogs.com/zhoujinyi/p/6073705.html
https://laravel-china.org/articles/3729/use-laravel-queue-to-understand-the-knowledge
https://www.jianshu.com/p/f8735b039c67?from=groupmessage
https://blog.youkuaiyun.com/zou79189747/article/details/80403016
相信看了上面的几篇文章,基本对 supervisor 就有一个大概的认识了,我总结的肯定没人家的好,这里简述下几个核心:
1>安装完 supervisor,总共有几个组件:
1)supervisord // 服务端(redis 的 redis-sever)
2)supervisorctl // 客户端(redis 的 redis-cli)
3)web-server 管理界面 // 我们可以通过 web 来查看
2>supervisor 的使用步骤:
1)先配置 supervisord
supervisord.conf
分几大块:
[unix_http_server] - socket 配置(方式1)
[inet_http_server] - TCP 配置(web-server 应该得使用它)(方式2)
[supervisord] - 服务端配置
[rpcinterface:supervisor] - RPC 接口相关,supervisor 和 web-server 必须开启
[supervisorctl] - 客户端配置
[eventlistener:theeventlistenername] - 事件监听(和 program 类似,应该是可以定义多个监听事件)
[group:thegroupname] - 将多个进程,划分到一个组,统一操作
[program:theprogramname] - 进程配置
[include] - 引入其他配置,我们将 '进程配置' 都放到独立的文件引入
2)配置我们自己的进程配置文件,尽量是每个进程单独配置个配置
在 supervisord.conf 最后,有个 include xxx,可以将我们自定义的进程配置文件载入
3)启动 supervisord
supervisord -c /xxx/supervisord.conf // 可以使用 -c 指定配置文件路径
4)可以启动 supervisorctl 客户端,来进行交互操作
supervisorctl -c /etc/supervisord.conf // 也可以使用 -c 指定配置文件路径(它的配置区块,和 supervisord 在同一个配置文件内)
supervisorctl --help // 查看命令使用
/usr/local/bin/supervisorctl [options] [action [arguments]]
可用的 action 有(使用 supervisorctl help 查看):
add
exit
open
reload
...
每个 action 的使用,可通过命令查看
supervisorctl help add
supervisorctl help exit
...
5)web server 访问:
http://localhost:9001/
4>laravel 队列的监听配置:
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /data/wwwroot/app/artisan queue:work redis --sleep=3 --tries=3
autostart=true
autorestart=true
;user=forge
numprocs=8
redirect_stderr=true
stdout_logfile=/data/wwwroot/app/storages/supervisor/worker.log
参考官方文档:
https://laravelacademy.org/post/8369.html#toc_17
1>mac 本地安装
安装:
brew install supervisor // 看提示依赖了 pkg-config, sphinx-doc, gdbm, openssl, sqlite and python@2,安装了十来分钟呢
安装完成后,提示了:
brew services start supervisor // 现在启动,并在登录时重新启动
supervisord -c /usr/local/etc/supervisord.ini // 默认是后台运行,希望前台运行
启动发现问题:
1)[program:theprogramname] 里有一个 user 配置。默认是禁用的,我们如果设置了 user,表示可以使用 user 来管理当前的 program。所以这个 user 必须是系统内存在的用户。
2)启动 supervisorctl 报错:
http://localhost:9001 refused connection
查看默认的 supervisorctl 配置:
/*
[unix_http_server]
file=/usr/local/var/run/supervisor.sock ; the path to the socket file
;chmod=0700 ; socket file mode (default 0700)
;chown=nobody:nogroup ; socket file uid:gid owner
;username=user ; default is no username (open server)
;password=123 ; default is no password (open server)
;[inet_http_server] ; inet (TCP) server disabled by default
;port=127.0.0.1:9001 ; ip_address:port specifier, *:port for all iface
;username=user ; default is no username (open server)
;password=123 ; default is no password (open server)
// 这里得说明下:
serverurl 有2种方式,就是上面的
unix_http_server
inet_http_server
默认是使用的 unix 配置,我们也可以开启 inet 配置
[supervisorctl]
serverurl=unix:///usr/local/var/run/supervisor.sock ; use a unix:// URL for a unix socket
;serverurl=http://127.0.0.1:9001 ; use an http:// url to specify an inet socket
*/
serverurl 我们配置的是 socket,而非 tcp
而 supervisorctl --help 可以看到:
-s/--serverurl URL -- URL on which supervisord server is listening
(default "http://localhost:9001")
默认是以 'tcp' 来请求的
解决方法:
1.修改 supervisorctl 的 serverurl 配置
2.启动 supervisorctl 时,指定 -s 参数
3)启动是启动了,又报错:
supervisor: couldn't setuid to 4294967294: Can't drop privilege as nonroot user
supervisor: child process was not spawned
屏蔽程序里的 ;user=xxx(其他定义 user 方法,没看)
/*
搞不定了。。。。。
127.0.0.1:9001 也一直被拒绝
还查了半天,开启 mac 端口的文章,都不行!!!
放弃!!!
等待高手解答!!!
*/
2>linux 服务器上安装
好多安装方式,推荐使用的这个,正好也有 easy_install 命令,就该方式安装:
easy_install supervisor
easy_install 安装方式,没有配置文件:
echo_supervisord_conf // 查看配置文件
echo_supervisord_conf > /etc/supervisord.conf // 生成配置文件
运行:
supervisord -c /etc/supervisord.conf
配置:
vim /etc/supervisord.conf
开启最下方的 [include],包含的文件目录为:/etc/supervisor.d/
mkdir /etc/supervisor.d
在 supervisor.d/ 下配置,各种进程的配置
web server 配置:
[inet_http_server]
port=127.0.0.1:9001
默认的 127.0.0.1:9001,通过 elinks,在服务器上确实可以访问!
但我们使用的是云服务器,得通过 '外网:9001' 来访问,死活不行!!!
对了,云服务器的 iptables 也必须开启 9001 端口
最终在一篇文章里,看到个配置,终于可以访问(我都不知道花了多久时间):
[inet_http_server]
port=*:9001
supervisor 退出、重启等,好像得使用 kill -HUP,搜索到一些文章来处理该问题:
1.kill -s SIGTERM $(supervisorctl pid)
2.supervisor 各个系统的启动脚本:
https://github.com/Supervisor/initscripts
3.https://www.load-page.com/manuals/web-server/chapter-tools/supervisor.html(这个比较给力,打算用这个)
2.horizon
参考文章:
https://laravelacademy.org/post/8492.html
安装:
composer require laravel/horizon
发布前端资源、配置:
php artisan vendor:publish --provider="Laravel\Horizon\HorizonServiceProvider"
配置文件:
config/horizon.php
运行:
php artisan horizon - 启动
php artisan horizon:pause - 暂停
php artisan horizon:continue - 继续
php artisan horizon:terminate - 优雅地终止,会在所有当前正在执行的任务全部完成后退出
进程监控:
使用上面提到的 supervisor 来管理
配置:
[program:horizon]
process_name=%(program_name)s
command=php /data/wwwroot/app/artisan horizon
autostart=true
autorestart=true
user=forge
redirect_stderr=true
stdout_logfile=/data/wwwroot/app/storages/supervisor/horizon.log
访问:
/horizon
访问限制,线上访问 horizon,我们需要设置访问策略(不用考虑配置个其他目录...):
AppServiceProvider -> boot() 调用
Horizon::auth(function ($request) {
// return true / false;
});
队列任务等待超时通知:
AppServiceProvider 调用不同的通知方法,取决于我们想使用哪种类型的通知
Horizon::routeMailNotificationsTo('example@example.com');
Horizon::routeSlackNotificationsTo('slack-webhook-url', '#channel');
Horizon::routeSmsNotificationsTo('15556667777');
config/horizon.php 配置 waits 来配置等待超时时间:
'waits' => [
'redis:default' => 60,
],
监控:
app/Console/Kernel.php 配置计划任务
// 监控后台查看任务和队列的等待时间和吞吐量信息,获取实时信息
$schedule->command('horizon:snapshot')->everyFiveMinutes();
记录一个问题:
horizon 官方文档有个警告:
注:由于 Horizon 使用了异步进程信号,所以 PHP 7.1+ 以上版本才可以使用。其次,你需要确保在 queue 配置文件中将队列驱动被设置为 redis。
要求我们的队列,必须是 redis。
而我们项目中的 redis,使用的是 『阿里云 redis』,应该是版本过低,一旦队列有数据,就会报错:
production.ERROR: ERR unknown command eval {"exception":"[object] (Predis\\Response\\ServerException(code: 0): ERR unknown command eval at /data/wwwroot/ pinxuejianyou_57/vendor/predis/predis/src/Client.php:370)
在测试服务器上测试,服务器上自身的 redis 是没有问题的!
这个问题,没有仔细研究,猜测是 redis 版本的问题
我们暂时将队列修改为:database 链接