[實戰]laravel + redis訂閱釋出 +swoole實現實時訂單通知

my38778570發表於2022-05-27
  1. redis生產者釋出

    php artisan make:command Redis/PublishCommand
  2. redis消費者訂閱

    php artisan make:command Redis/SubCommand
  3. 啟動websocket

    php artisan ws
<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Redis;
use App\Facades\MyRedis;

class WebSocket extends Command
{
    protected $signature = 'ws';

    protected $ws;

    public function __construct()
    {
        parent::__construct();
    }

    public function handle()
    {
        //建立websocket伺服器物件,監聽0.0.0.0:9502埠,開啟SSL隧道
        $this->ws = new \swoole_websocket_server("0.0.0.0", 9502, SWOOLE_PROCESS, SWOOLE_SOCK_TCP | SWOOLE_SSL);

        //配置引數
        $this->ws ->set([
            'daemonize' => false, //守護程式化。
            //配置SSL證照和金鑰路徑
            'ssl_cert_file' => env('SSL_CERT_FILE'),
            'ssl_key_file'  => env('SSL_KEY_FILE')
        ]);

        $this->ws->on("open", function (\Swoole\WebSocket\Server $ws, \Swoole\Http\Request $request) {
//            dump($request->fd, $request->get, $request->server);
            $ws->push($request->fd, "連線成功\n");
        });

        $this->ws->on("message", function (\Swoole\WebSocket\Server $ws, $frame) {
//            dump("訊息: {$frame->data}\n");
            $ws->push($frame->fd, "服務端回覆: {$frame->data}\n");
        });

        //監聽WebSocket主動推送訊息事件
        $this->ws->on('request', function ($request, $response) {
            $data = $request->post;
            //$this->ws->connections 遍歷所有websocket連線使用者的fd,給所有使用者推送
            foreach ($this->ws->connections as $fd) {
                if ($this->ws->isEstablished($fd)) {
                    $this->ws->push($fd, json_encode($data));
                }
            }
        });

        $this->ws->on("close", function (\Swoole\WebSocket\Server $ws, $fd) {
            dump("{$fd}關閉");
        });

        $this->ws->start();
    }

}
  1. 啟動redis消費者訂閱
    php artisan sub:info
<?php

namespace App\Console\Commands\Redis;

use App\Facades\MyRedis;
use Illuminate\Console\Command;

class SubCommand extends Command
{

    protected $signature = 'sub:info';


    protected $description = 'redis消費者訂閱';


    public function __construct()
    {
        parent::__construct();
    }


    public function handle()
    {
        MyRedis::subScribe();
        $this->comment('sub successful');
    }
}
  1. h5頁面連線websocket
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>websocket</title>
</head>

<body>
    <script>
        var wsServer = 'wss://test.自己域名.com:9502';
        var websocket = new WebSocket(wsServer);
        websocket.onopen = function (evt) {
            console.log("Connected to WebSocket server.");
        };

        websocket.onclose = function (evt) {
            console.log("Disconnected");
        };

        websocket.onmessage = function (evt) {
            console.log('Retrieved data from server: ' + evt.data);
        };

        websocket.onerror = function (evt, e) {
            console.log('Error occured: ' + evt.data);
        };
    </script>

</body>

</html>

laravel + redis訂閱釋出 +swoole

  1. redis生產者釋出
    php artisan publish:info
<?php

namespace App\Console\Commands\Redis;

use App\Facades\MyRedis;
use Illuminate\Console\Command;

class PublishCommand extends Command
{

    protected $signature = 'publish:info';

    protected $description = 'redis生產者釋出';


    public function __construct()
    {
        parent::__construct();
    }

    public function handle()
    {
        $data = [
            'orders_id' => 1
        ];
        MyRedis::publish($data);
        $this->comment('publish successful');
    }
}

[實戰]laravel + redis訂閱釋出 +swoole實現實時訂單通知

  1. 檢視h5 websocket頁面實時返回通知結果

laravel + redis訂閱釋出 +swoole

相關Facades程式碼

<?php

namespace App\Facades;

use App\Services\MyRedis\MyRedisService;
use Illuminate\Support\Facades\Facade;

/**
 * Class Response
 * @package App\Facades
 * @method static boolean publish(array $data)
 * @method static subScribe()
 */

class MyRedis extends Facade
{
    protected static function getFacadeAccessor()
    {
        return MyRedisService::class;
    }
}
<?php

namespace App\Services\MyRedis;

use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;

class MyRedisService
{
    protected $subKey = 'ordersRemind';//訂單提醒

    //生產者釋出
    public function publish(array $data) : bool
    {
        try {
            Redis::publish($this->subKey, json_encode($data));
        } catch (\Exception $exception) {
            Log::error($exception->getMessage());
            return false;
        }
        return true;
    }

    //消費者訂閱
    public function subScribe()
    {
        set_time_limit(0);
        ini_set('default_socket_timeout', -1);
        try {
            echo 'start' . "\n";
            Redis::subscribe($this->subKey, function ($json, $message) {
                $url = "https://test.自己的域名.com:9502";
                MyRedisService::httpPost($url, json_decode($json,true));
            });
        } catch (\Exception $exception) {
            Log::error($exception->getMessage());
        }
    }

    public static function httpPost($url, $param){
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl, CURLOPT_HEADER, 1);
        curl_setopt($curl, CURLOPT_POST, 1);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $param);
        curl_exec($curl);
        curl_close($curl);
    }
}

[實戰]laravel + redis訂閱釋出 +swoole實現實時訂單通知

守護程式

  1. 藉助 nohup 和 & 配合使用
    nohup php artisan sub:info &
  2. 透過 fg 命令讓程式恢復到普通佔用控制檯的模式
    fg

關閉程式

netstat -anp | grep 9502
kill -9 1682674

相關文件
php實現守護程式的兩種常見方式

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章