各位老哥问下,webman有没有类似laravel-cache的原子锁功能?
文档: https://learnku.com/docs/laravel/6.x/cache/5160#atomic-locks
自问自答 :
按照webman文档cache章节,安装完扩展之后,在support下增加下面两个类, 类是复制laravel框架的, 改了一点东西, 最后有使用方法.
Lock.php
<?php
namespace support;
use Illuminate\Contracts\Cache\Lock as LockContract;
use Illuminate\Contracts\Cache\LockTimeoutException;
use Illuminate\Support\InteractsWithTime;
use Illuminate\Support\Str;
abstract class Lock implements LockContract
{
use InteractsWithTime;
/**
* The name of the lock.
*
* @var string
*/
protected $name;
/**
* The number of seconds the lock should be maintained.
*
* @var int
*/
protected $seconds;
/**
* The scope identifier of this lock.
*
* @var string
*/
protected $owner;
/**
* Create a new lock instance.
*
* @param string $name
* @param int $seconds
* @param string|null $owner
* @return void
*/
public function __construct($name, $seconds, $owner = null)
{
if (is_null($owner)) {
$owner = Str::random();
}
$this->name = $name;
$this->owner = $owner;
$this->seconds = $seconds;
}
/**
* Attempt to acquire the lock.
*
* @return bool
*/
abstract public function acquire();
/**
* Release the lock.
*
* @return bool
*/
abstract public function release();
/**
* Returns the owner value written into the driver for this lock.
*
* @return string
*/
abstract protected function getCurrentOwner();
/**
* Attempt to acquire the lock.
*
* @param callable|null $callback
* @return mixed
*/
public function get($callback = null)
{
$result = $this->acquire();
if ($result && is_callable($callback)) {
try {
return $callback();
} finally {
$this->release();
}
}
return $result;
}
/**
* Attempt to acquire the lock for the given number of seconds.
*
* @param int $seconds
* @param callable|null $callback
* @return bool
*
* @throws \Illuminate\Contracts\Cache\LockTimeoutException
*/
public function block($seconds, $callback = null)
{
$starting = $this->currentTime();
while (! $this->acquire()) {
usleep(250 * 1000);
if ($this->currentTime() - $seconds >= $starting) {
throw new LockTimeoutException;
}
}
if (is_callable($callback)) {
try {
return $callback();
} finally {
$this->release();
}
}
return true;
}
/**
* Returns the current owner of the lock.
*
* @return string
*/
public function owner()
{
return $this->owner;
}
/**
* Determines whether this lock is allowed to release the lock in the driver.
*
* @return bool
*/
protected function isOwnedByCurrentProcess()
{
return $this->getCurrentOwner() === $this->owner;
}
}
RedisLock.php
<?php
namespace support;
class RedisLock extends Lock
{
/**
* The Redis factory implementation.
*
* @var \Illuminate\Redis\Connections\Connection
*/
protected $redis;
/**
* Create a new lock instance.
*
* @param \Illuminate\Redis\Connections\Connection $redis
* @param string $name
* @param int $seconds
* @param string|null $owner
* @return void
*/
public function __construct($redis, $name, $seconds, $owner = null)
{
parent::__construct($name, $seconds, $owner);
$this->redis = $redis;
}
/**
* Attempt to acquire the lock.
*
* @return bool
*/
public function acquire()
{
if ($this->seconds > 0) {
return $this->redis->set($this->name, $this->owner, 'EX', $this->seconds, 'NX') == true;
}
return $this->redis->setnx($this->name, $this->owner) === 1;
}
/**
* Release the lock.
*
* @return bool
*/
public function release()
{
return (bool) $this->redis->eval(self::releaseLock(), 1, $this->name, $this->owner);
}
public static function releaseLock()
{
return <<<'LUA'
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
LUA;
}
/**
* Releases this lock in disregard of ownership.
*
* @return void
*/
public function forceRelease()
{
$this->redis->del($this->name);
}
/**
* Returns the owner value written into the driver for this lock.
*
* @return string
*/
protected function getCurrentOwner()
{
return $this->redis->get($this->name);
}
}
最后用法如下:
indexController.php下:
public function test(Request $request)
{
/**
* @var $lock RedisLock
*/
$lock = Container::instance()->make(RedisLock::class, [Redis::connection(), 'foo', 10]); //::lock('foo', 10);
try {
$lock->block(5);
// 等待最多5秒后获取的锁...
} catch (LockTimeoutException $e) {
// 无法获取锁...
throw $e;
} finally {
optional($lock)->release();
}
return json(['code' => 1, 'msg' => 'ok']);
}
没有
老哥,可以同步到分享区域么?
好像运行不起来
有错误日志么?
换 tp Container. Container::getInstance()->make() 可以了 webman的这个 Container::instance()->make(使用 不 起来
我这边用的就是 webman的这个 Container::instance()->make,没问题呀。
待会,我也试试TP的Container
你是不是没有用 依赖自动注入
报错信息
DI\Definition\Exception\InvalidDefinition: Entry "support\RedisLock" cannot be resolved: Entry "Illuminate\Redis\Connections\Connection" cannot be resolved: the class is not instantiable
Full definition:
Object (
class = #NOT INSTANTIABLE# Illuminate\Redis\Connections\Connection
lazy = false
)
Full definition:
Object (
class = support\RedisLock
lazy = false
__construct(
$redis = get(Illuminate\Redis\Connections\Connection)
$name = #UNDEFINED#
$seconds = #UNDEFINED#
$owner = (default value) NULL
)
我用了webman的Container,你用的DI扩展,不一样的。
用webman肯定要开启 依赖注入的
默认用的就是 Webman\Container; DI扩展可能是不兼容吧, 要用锁的话,可以用其他的类
基于 symfony/lock
https://github.com/yzh52521/webman-lock
mark
mark+1