場景使用:假設(shè)有一個訂單 30 分鐘以后未付款 自動關(guān)閉該訂單潘懊》谱欤或者會員到期自動提醒續(xù)費等等拘哨。
這個在 Laravel 中其實有更好的選擇方式 隊列,使用延時隊列
ProcessPodcast::dispatch($podcast)->delay(now()->addMinutes(30));
但是我還想到一種方案就是使用?Redis?的鍵空間通知(keyspace notification)互广。意思就是當 Redis 的 key 刪除是,回主動通知發(fā)送消息給我們,我們只需要監(jiān)聽訂閱對應(yīng)的事件即可惫皱。
接下來我還原事情經(jīng)過像樊。說一下我遇到的問題,以及最后是如何解決的旅敷。
首先 Redis 的?keyspace notification?默認是不開啟的生棍。我們需要主動開啟,開啟方式如下 修改 redis.conf 配置文件 找到?notify-keyspace-events ""?默認是空字符串媳谁,表示未開啟.
notify-keyspace-events "Ex"
然后重啟?Redis
或者直接 redis-cli 下輸入如下命令進行修改
redis-cli configsetnotify-keyspace-eventsEx
具體?Ex?代表啥意思 參考如下表格:
接下來在 Laravel 中涂滴,我是新建一個 Command 命令
php artisan make:commandOrderExpire
內(nèi)容如下:
<?phpnamespace App\Console\Commands;use Illuminate\Console\Command;use Illuminate\Support\Facades\Redis;classOrderExpireextendsCommand{
? ? /**? ? * The name and signature of the console command.? ? *? ? *@varstring? ? */? ? protected $signature = 'order:expire';
? ? /**? ? * The console command description.? ? *? ? *@varstring? ? */? ? protected $description = '處理訂單失效';
? ? /**? ? * Create a new command instance.? ? *? ? *@returnvoid? ? */? ? public function__construct(){
? ? ? ? parent::__construct();
? ? }
? ? /**? ? * Execute the console command.? ? *? ? *@returnint? ? */? ? public functionhandle(){
? ? ? ? $redis = Redis::connection('publisher');
? ? ? ? Redis::subscribe(['__keyevent@0__:expired'], function($message, $channel){
? ? ? ? ? ? // 處理訂單失效 邏輯? ? ? ? ? ? echo '訂單已失效';
? ? ? ? });
? ? }
}
?>
在?config?下?database.php?中 redis 配置里添加 如下內(nèi)容:
'publisher' => [
? ? 'host' => env('REDIS_HOST', '127.0.0.1'),
? ? 'password' => env('REDIS_PASSWORD', null),
? ? 'port' => env('REDIS_PORT', 6379),
? ? 'database' => 0,
? ? 'read_timeout' => 0,
? ? 'persistent' => true,
? ? 'read_write_timeout' => 0,
],
在 路由文件下 編寫?Redis?鍵 到期命令晴音,設(shè)置 5 秒失效
use Illuminate\Support\Facades\Redis;
Route::get('/', function(){
? ? Redis::setex('order_2000123421',5,'2000123421');
});
接下來運行行項目
我們首先在 Laravel 項目中運行 控制臺命令
php? artisan? order:expire
接下來在 red-cli 中也監(jiān)聽過期命令
redis-cli127.0.0.1:6379> psubscribe __keyevent@0__:expired
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "__keyevent@0__:expired"
3) (integer) 1
1) "pmessage"
2) "__keyevent@0__:expired"
3) "__keyevent@0__:expired"
訪問路由文件柔纵,設(shè)置 Redis Key,但是你會發(fā)現(xiàn)實際上我們編寫的控制臺命令锤躁,Redis 5 秒過后并不會觸發(fā)任何事件搁料。而 redis-cli 5 秒以后會監(jiān)聽到。
下面是 redis-cli 的結(jié)果:?
下圖是 Laravel 項目的結(jié)果进苍,過一定事件還會出現(xiàn)連接錯誤:
這個問題糾結(jié)了挺久加缘。最后解決方案如下:
解決方案
不使用 Laravel 自帶的?Redis?門面,改為原生?Redis?觉啊。修改 handle 方法
$redis = new \Redis();
$redis->connect('127.0.0.1', '6379');
$redis->auth('Reids密碼');
$redis->setOption(\Redis::OPT_READ_TIMEOUT, -1);
$redis->subscribe(['__keyevent@0__:expired'], function($instance,$channelName, $message) {
? ? ? ? ? ? ? ? var_dump($channelName);
? ? var_dump($message);
});