当前位置: 首页 > 后端技术 > PHP

MixPHPV2.1生态:Swoole协程Redis订阅器

时间:2023-03-29 14:27:53 PHP

OpenMix全家桶中有一个MixRedisSubscribe项目。这是一个不依赖phpredis扩展,直接解析Redis协议专用于订阅处理的库。任何Swoole框架都可以使用,并且可以广泛用于WebSocket开发,并且这个库也默认包含在MixPHP框架中。为什么开发MixPHPV2.1开发完成后,尝试开发一个基于订阅的WebScoket服务,需要动态切换订阅通道,但是phpredis的订阅方法无法实现如下功能:$redis=new\Redis();$res=$redis->pconnect('127.0.0.1',6379,0);$redis->subscribe(['test'],function($instance,$channelName,$message){echo$channelName,"==>",$message,PHP_EOL;});上面代码中,当执行订阅时,会阻塞执行,只有有消息时才会执行匿名函数,订阅成功时不会执行。执行关闭,但是当redis-cli执行订阅的时候,redis-server回复了订阅成功的信息,所以是phpredis的设计问题。无法动态订阅添加频道由于subscribe会阻塞执行,代码只能在消息触发回调时在回调中执行,所以动态添加频道也是无法操作的。unsubscribe因为上面的阻塞式回调设计,只能在回调中执行,如果需要取消一个频道,只有在有消息的情况下才能操作,但实际需求通常是需要随时取消频道.无法在其他协程中关闭连接phpredis在尝试关闭匿名函数以外的协程中的连接时,会抛出异常PHPFatalerror:UncaughtRedisException:readerroronconnection,导致无法关闭其中的redis连接订阅优雅地实现。当我了解到redis协议是一个简单的文本协议后,我决定放弃phpredis,建立一个有用的订阅库。新轮子有以下优点:不依赖phpredis扩展,修改流畅:可以随时添加和取消订阅频道,实现频道无缝切换的需要。跨协程安全关闭:可以随时关闭订阅。通过channel获取消息:该库的封装方式参考了golang语言对go-redis库的封装,通过channel获取订阅的消息。$sub=new\\Mix\\Redis\\Subscribe\\Subscriber('127.0.0.1',6379,'',5);//如果连接失败,将抛出异常$sub->subscribe('foo','bar');//订阅失败会抛出异常$chan=$sub->channel();while(true){$data=$chan->pop();if(empty($data)){//手动关闭和redis异常断开都会返回falseif(!$sub->closed){//Redis异常断开处理var_dump('Redis连接异常断开');}休息;}var_dump($data);}收到订阅消息:object(Mix\Redis\Subscribe\Message)#8(2){["channel"]=>string(2)"foo"["payload"]=>string(4)"测试"}