redis鍵過期通知

背景概要

  • 背景:為了防止用戶長時間不確認收貨,需要對訂單做24小時后自動確認收貨處理
  • 方案:利用Redis的鍵空間通知和發(fā)布訂閱機制,結合nohup掛載命令后臺守護進程監(jiān)聽,可實現(xiàn)Redis的key過期自動提醒
  • 結果:最終實現(xiàn)訂單確認收貨超時自動化

其他方案

一開始想到的是cron定時任務,雖然可以勉強滿足但不是最佳方案,訂單數(shù)少的時候很浪費資源

實現(xiàn)

修改redis配置

因為開啟鍵空間通知功能需要消耗一些 CPU , 所以在默認配置下, 該功能處于關閉狀態(tài)。

參數(shù)說明.png
127.0.0.1:6379> config get notify-keyspace-events
1) "notify-keyspace-events"
2) ""
127.0.0.1:6379> config set notify-keyspace-events Ex
OK
127.0.0.1:6379> config get notify-keyspace-events
1) "notify-keyspace-events"
2) "xE"

其實不建議用上面的辦法,因為config是危險命令,生產(chǎn)環(huán)境禁用,任何客戶端都能隨便獲取配置修改配置,只要客戶端連接成功就能隨意篡改,只能在測試服使用

Centos修改配置方法還不太一樣

修改文件/etc/redis.conf

redis-cli shutdown
redis-server /etc/redis.conf &

vim /etc/redis.conf

此時重新進入 redis-cli 查看 config get notify-keyspace-events 就看到配置生效了

重啟redis

/etc/init.d/redis-server restart

redis修改了配置文件,但是一直不生效怎么辦,看這篇https://www.cnblogs.com/foundwant/p/5552807.html

鍵空間通知演示

127.0.0.1:6379> setex name 10 shizhenfeng
OK

再打開一個終端,10秒之后~

127.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"
4) "name"

結合Laravel artisan實現(xiàn)

創(chuàng)建命令

php artisan make:command OrderExpireListen

代碼如下

<?php

namespace App\Console\Commands;

use App\Models\Order;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Redis;

class OrderExpireListen extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'order:expire';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '24小時自動確認收貨';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $pattern = '__keyevent@0__:expired';
        Redis::subscribe($pattern, function ($channel) {     // 訂閱鍵過期事件
            // 鍵格式:order_confirm:34
            $keyType = str_before($channel, ':');
            switch ($keyType) {
                case 'order_confirm':
                    $orderId = str_after($channel, ':');
                    $order = Order::find($orderId);
                    if ($order) {
                        $order->status = 5;
                        $order->save();
                        \Log::info("訂單 {$order->id} 自動確認收貨");
                    }
                    break;
                case 'order_other':
                    // 其他事件,如訂單15分鐘內(nèi)未支付自動取消訂單
                    break;
                default:
                    break;
            }
        });
    }
}

控制器

    // redis鍵空間通知
    $key = 'order_confirm:' . $order->id;
    $seconds = 24 * 60 * 60;
    // 值無所謂,關鍵是key
    Redis::setex($key, $seconds, 1);

報錯記錄

Error while reading line from the server. [tcp://127.0.0.1:6379]

解決辦法:

config/database.php 添加一行

'redis' => [

        'client' => 'predis',

        'default' => [
            'host' => env('REDIS_HOST', '127.0.0.1'),
            'password' => env('REDIS_PASSWORD', null),
            'port' => env('REDIS_PORT', 6379),
            'database' => 0,
            'read_write_timeout' => 0,  // <----這一條是新加的
        ],

    ],

如何使監(jiān)聽后臺始終運行

redis 在執(zhí)行完訂閱操作后,終端進入阻塞狀態(tài),需要一直掛在那。且此訂閱腳本需要人為在命令行執(zhí)行,不符合實際需求。

實際上,我們對過期監(jiān)聽回調的需求,是希望它像守護進程一樣,在后臺運行,當有過期事件的消息時,觸發(fā)回調函數(shù)。 使監(jiān)聽后臺始終運行 希望像守護進程一樣在后臺一樣,

Linux中有一個nohup命令。功能就是不掛斷地運行命令。 同時nohup把腳本程序的所有輸出,都放到當前目錄的nohup.out文件中,如果文件不可寫,則放到<用戶主目錄>/nohup.out 文件中。那么有了這個命令以后,不管我們終端窗口是否關閉,都能夠讓我們的php腳本一直運行。

local環(huán)境
nohup php /var/www/wine/artisan order:expire >> /var/www/wine/storage/logs/nohup.log 2>&1 &

dev環(huán)境
nohup /usr/bin/php /var/www/html/wine/artisan order:expire >> /var/www/html/wine/storage/logs/nohup.log 2>&1 &

如何證明命令掛上去了

方法一
ps -ef |grep php
控制臺輸出
root      1216     1  0 01:10 ?        00:00:02 php-fpm: master process (/etc/php/7.1/fpm/php-fpm.conf)
vagrant   1473  1216  0 01:10 ?        00:00:01 php-fpm: pool www
vagrant   1484  1216  0 01:10 ?        00:00:00 php-fpm: pool www
vagrant   1489     1  0 01:10 ?        00:00:01 /usr/bin/hhvm --config /etc/hhvm/php.ini --config /etc/hhvm/server.ini --user vagrant --mode daemon -vPidFile=/var/run/hhvm/pid
vagrant   7909  2842  0 08:24 pts/0    00:00:00 php /var/www/wine/artisan order:expire   <--------看,這里就有了吧
vagrant   7974  2842  0 08:29 pts/0    00:00:00 grep --color=auto php

方法二(只對當前會話有效,關掉窗口就看不到了)
jobs -l
控制臺輸出
[1]+  7909 Running                 nohup php /var/www/wine/artisan order:expire >> /var/www/wine/storage/logs/nohup.log 2>&1 &

拓展

還能用到哪些需求,比如未支付訂單定時關閉

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容