diff --git a/app/Cache/Contracts/LockRedisInterface.php b/app/Cache/Contracts/LockRedisInterface.php index ca8c952..aeadab6 100644 --- a/app/Cache/Contracts/LockRedisInterface.php +++ b/app/Cache/Contracts/LockRedisInterface.php @@ -4,7 +4,7 @@ namespace App\Cache\Contracts; interface LockRedisInterface { - public function lock(string $key, $lockTime = 1, $timeout = 0); + public function lock(string $key, $expired = 1, int $timeout = 0); public function delete(string $key); } diff --git a/app/Cache/Repository/LockRedis.php b/app/Cache/Repository/LockRedis.php index 00d4cbc..6a2dc1a 100644 --- a/app/Cache/Repository/LockRedis.php +++ b/app/Cache/Repository/LockRedis.php @@ -3,6 +3,8 @@ namespace App\Cache\Repository; use App\Cache\Contracts\LockRedisInterface; +use Swoole\Coroutine; +use Exception; /** * Redis Lock @@ -13,40 +15,33 @@ class LockRedis extends AbstractRedis implements LockRedisInterface { protected $prefix = 'rds-lock'; - protected $lockValue = 1; - - /** - * 获取是毫秒时间戳 - * - * @return int - */ - private function time() - { - return intval(microtime(true) * 1000); - } + protected $value = 1; /** * 获取 Redis 锁 * - * @param string $key 锁标识 - * @param int $lockTime 过期时间/秒 - * @param int $timeout 获取超时/毫秒 + * @param string $key 锁标识 + * @param int $expired 过期时间/秒 + * @param int $timeout 获取超时/秒,默认每隔 0.1 秒获取一次锁 * @return bool */ - public function lock(string $key, $lockTime = 1, $timeout = 0) + public function lock(string $key, $expired = 1, int $timeout = 0) { $lockName = $this->getCacheKey($key); - $start = $this->time(); + // 重复获取次数 + $retry = $timeout > 0 ? intdiv($timeout * 100, 10) : 1; do { - $lock = $this->redis()->set($lockName, $this->lockValue, ['nx', 'ex' => $lockTime]); + $lock = $this->redis()->set($lockName, $this->value, ['nx', 'ex' => $expired]); if ($lock || $timeout === 0) { break; } // 默认 0.1 秒一次取锁 - usleep(100000); - } while ($this->time() < $start + $timeout); + Coroutine::getCid() ? Coroutine::sleep(0.1) : usleep(100000); + + $retry--; + } while ($retry); return $lock; } @@ -67,6 +62,31 @@ class LockRedis extends AbstractRedis implements LockRedisInterface end LAU; - return $this->redis()->eval($script, [$this->getCacheKey($key), $this->lockValue], 1); + return $this->redis()->eval($script, [$this->getCacheKey($key), $this->value], 1); + } + + /** + * 获取锁并执行 + * + * @param \Closure $closure 闭包函数 + * @param string $lock_name 锁名 + * @param int $expired 过期时间/秒 + * @param int $timeout 获取超时/秒 + * @return bool + * @throws Exception + */ + public function try(\Closure $closure, string $lock_name, int $expired = 1, int $timeout = 0) + { + if (!$this->lock($lock_name, $expired, $timeout)) return false; + + try { + call_user_func($closure); + } catch (Exception $e) { + throw $e; + } finally { + $this->delete($lock_name); + } + + return true; } } diff --git a/app/Command/TestCommand.php b/app/Command/TestCommand.php index 9e20570..5b06283 100644 --- a/app/Command/TestCommand.php +++ b/app/Command/TestCommand.php @@ -49,9 +49,9 @@ class TestCommand extends HyperfCommand public function handle() { - //$lock = LockRedis::getInstance(); + $lock = LockRedis::getInstance(); //var_dump($lock->delete('ttt')); - //var_dump($lock->lock('ttt', 180)); + //var_dump($lock->lock('ttt', 180, 5)); //$string = StringRedis::getInstance(); //var_dump($string->set('yuandong', 'dong', 30)); diff --git a/app/Controller/TestController.php b/app/Controller/TestController.php index 814d7b7..efe13e0 100644 --- a/app/Controller/TestController.php +++ b/app/Controller/TestController.php @@ -9,12 +9,13 @@ use Hyperf\HttpServer\Annotation\RequestMapping; /** * 测试相关控制器 * @Controller() + * * @package App\Controller */ class TestController extends AbstractController { /** - * @RequestMapping(path="indexss", methods="get") + * @RequestMapping(path="index", methods="get") */ public function index() { diff --git a/app/Process/RedisExpiredSubscribe.php b/app/Process/RedisExpiredSubscribe.php new file mode 100644 index 0000000..ba150b6 --- /dev/null +++ b/app/Process/RedisExpiredSubscribe.php @@ -0,0 +1,39 @@ +psubscribe(['__keyevent@5__:expired'], [$this, 'subscribe']); + } + + /** + * 过期键回调处理 + * + * @param $redis + * @param $pattern + * @param $chan + * @param $msg + */ + public function subscribe($redis, $pattern, $chan, $msg) + { + echo "Pattern: $pattern\n"; + echo "Channel: $chan\n"; + echo "Payload: $msg\n\n"; + } + + public function isEnable($server): bool + { + return false; + } +} diff --git a/app/Process/RedisSubscribe.php b/app/Process/RedisSubscribe.php new file mode 100644 index 0000000..5bf5df2 --- /dev/null +++ b/app/Process/RedisSubscribe.php @@ -0,0 +1,43 @@ +subscribe($this->chans, [$this, 'subscribe']); + } + + /** + * 订阅处理逻辑 + * + * @param $redis + * @param string $chan + * @param string $msg + */ + public function subscribe($redis, string $chan, string $msg) + { + echo PHP_EOL . "chan : $chan , msg : $msg"; + } + + public function isEnable($server): bool + { + return false; + } +} diff --git a/config/autoload/redis.php b/config/autoload/redis.php index 3180b62..ac3b60d 100644 --- a/config/autoload/redis.php +++ b/config/autoload/redis.php @@ -23,5 +23,8 @@ return [ 'heartbeat' => -1, 'max_idle_time' => (float) env('REDIS_MAX_IDLE_TIME', 60), ], + 'options' => [ + \Redis::OPT_READ_TIMEOUT => -1, + ], ], ];