标签:exp back ever [1] mes 行业 call should cte
app(‘redis‘)->connection(‘default‘)->throttle(‘key000‘) // 每60秒,只能有10个资源被获取,在3秒内获取不到锁抛出异常 ->allow(10)->every(60)->block(3) ->then(function () { // 获取锁成功,执行业务 }, function () { // 获取锁失败 return false; });
<?php namespace Illuminate\Redis\Limiters; use Illuminate\Contracts\Redis\LimiterTimeoutException; class DurationLimiter { /** * The Redis factory implementation. * * @var \Illuminate\Redis\Connections\Connection */ private $redis; /** * The unique name of the lock. * * @var string */ private $name; /** * The allowed number of concurrent tasks. * * @var int */ private $maxLocks; /** * The number of seconds a slot should be maintained. * * @var int */ private $decay; /** * The timestamp of the end of the current duration. * * @var int */ public $decaysAt; /** * The number of remaining slots. * * @var int */ public $remaining; /** * Create a new duration limiter instance. * * @param \Illuminate\Redis\Connections\Connection $redis * @param string $name * @param int $maxLocks * @param int $decay * @return void */ public function __construct($redis, $name, $maxLocks, $decay) { $this->name = $name; $this->decay = $decay; $this->redis = $redis; $this->maxLocks = $maxLocks; } /** * Attempt to acquire the lock for the given number of seconds. * * @param int $timeout * @param callable|null $callback * @return bool * @throws \Illuminate\Contracts\Redis\LimiterTimeoutException */ public function block($timeout, $callback = null) { $starting = time(); while (! $this->acquire()) { if (time() - $timeout >= $starting) { throw new LimiterTimeoutException; } usleep(750 * 1000); } if (is_callable($callback)) { $callback(); } return true; } /** * Attempt to acquire the lock. * * @return bool */ public function acquire() { $results = $this->redis->eval($this->luaScript(), 1, $this->name, microtime(true), time(), $this->decay, $this->maxLocks ); $this->decaysAt = $results[1]; $this->remaining = max(0, $results[2]); return (bool) $results[0]; } /** * Get the Lua script for acquiring a lock. * * KEYS[1] - The limiter name * ARGV[1] - Current time in microseconds * ARGV[2] - Current time in seconds * ARGV[3] - Duration of the bucket * ARGV[4] - Allowed number of tasks * * @return string */ protected function luaScript() { return <<<‘LUA‘ local function reset() redis.call(‘HMSET‘, KEYS[1], ‘start‘, ARGV[2], ‘end‘, ARGV[2] + ARGV[3], ‘count‘, 1) return redis.call(‘EXPIRE‘, KEYS[1], ARGV[3] * 2) end if redis.call(‘EXISTS‘, KEYS[1]) == 0 then return {reset(), ARGV[2] + ARGV[3], ARGV[4] - 1} end if ARGV[1] >= redis.call(‘HGET‘, KEYS[1], ‘start‘) and ARGV[1] <= redis.call(‘HGET‘, KEYS[1], ‘end‘) then return { tonumber(redis.call(‘HINCRBY‘, KEYS[1], ‘count‘, 1)) <= tonumber(ARGV[4]), redis.call(‘HGET‘, KEYS[1], ‘end‘), ARGV[4] - redis.call(‘HGET‘, KEYS[1], ‘count‘) } end return {reset(), ARGV[2] + ARGV[3], ARGV[4] - 1} LUA; } }
标签:exp back ever [1] mes 行业 call should cte
原文地址:https://www.cnblogs.com/xiaoyaogege/p/10724306.html