PHP+Redisによる遅延タスクの実現

3544 ワード

需要:ある注文が一定時間以内に支払われていない場合は、自動的にキャンセルされます.
以前は会社でLinuxのタイミングタスクを使用していましたが、全表スキャンで未払いの注文をスキャンし、期限が切れたかどうかを判断し、期限が切れた場合は注文の状態を変更します.これにより、全表スキャンを使用しているため、業務量が大きい場合、効率が低下します.
Redisアプリケーション:redisのkeyspace notificationsはkeyが失効した後にイベントを送信し、このイベントを傍受しているクライアントは通知を受け取ることができます(この機能はredis 2.8バージョン以降に発売されているので、サーバ上のreidsは少なくとも2.8バージョン以上であることに注意してください).
--------------------------------------------------------------------------
まずRedis構成の変更(Linuxシステム)
Redisプロファイルredisを開きます.conf
デフォルトの
notify-keyspace-events ""

に改心
notify-keyspace-events "Ex"

その後Redisを再起動します
---------------------------------------------------------------------------------
コードは簡単に書きました.必要なビジネスロジックは必要に応じて書きます.
データテーブル構造:
CREATE TABLE `shop_order` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `orderid` varchar(20) NOT NULL DEFAULT '' COMMENT '  id',
 `pay` tinyint(4) NOT NULL DEFAULT '0' COMMENT '     0:    1:   ',
 `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '     0:    1:      ',
 `createtime` int(11) NOT NULL COMMENT '      ',
 PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=27 DEFAULT CHARSET=utf8

PHPファイル名index.phpコード
try {
    $dsn         = 'mysql:host=127.0.0.1;dbname=shop;';
    $userName    = 'root';
    $passWord    = 'root';
    $pdo         = new PDO($dsn, $userName, $passWord);
    $orderid     = uniqid();
    $createTime  = time();
    /*       MySql                */
    $sql = "INSERT shop_order (orderid,createtime) VALUES ('$orderid','$createTime')";
    $pdo->exec($sql);
    /*       Redis                */
    $redis = new Redis();
    $redis->connect('127.0.0.1','6379');
    //   10s   
    $redis->setex($orderid,10,$orderid);
} catch (PDOException $e) {
    die ($e->getMessage());
}

index.phpの機能は、簡単に注文番号をデータベースとRedisに書き込み、Redisデータの有効期限(つまり注文の有効期限)を設定することです.
PHPファイル名sub.phpコード
keyevent@__:expiredというフォーマットは固定されており、dbはデータベースの番号を表しており、サブスクリプションがオンになると、このライブラリのすべてのkeyの有効期限がプッシュされます.
ini_set('default_socket_timeout', -1);
$redis = new Redis();
$res = $redis->connect('127.0.0.1', '6379');
$redis->setOption(Redis::OPT_READ_TIMEOUT, -1);
$redis->subscribe(array('__keyevent@0__:expired'), @function ($redis, $pattern, $channel, $msg){
    $orderid = $channel;
    echo '    '.$channel.'    ,          .....\r
'; $userName = 'root'; $passWord = 'root'; $dsn = 'mysql:host=127.0.0.1;dbname=shop;'; $pdo = new PDO($dsn, $userName, $passWord); // $sql1 = "SELECT * FROM shop_order WHERE status = 0 and pay = 0 and orderid = '$orderid'"; $incRes = $pdo->query($sql1); if($incRes && $incRes->rowCount()){ // $sql2 = "update shop_order set `status` = 1 where orderid = '$orderid'"; $upRes = $pdo->exec($sql2); if($upRes){ echo " :{$orderid} ....\r
"; } } });

sub.phpの機能はkeyが失効した後にイベントを送信し、ここで通知を受け取り、注文番号を受け取り、注文の状態を設定することです.
テスト:
スクリプトを使用してsub.phpを実行します
ブラウザでindexを実行します.php(数秒後にRedisのキーが期限切れになると、私のコンソールが現れます......)
注文番号は全部手に入れましたが...他に何かできないことはありますか?
個人ブログ:https://www.521bug.cn