limit and math.max(1, ttl) > retry then blocked = i retry = math.max(1, ttl) end end if blocked > 0 then local notice = redis.call('SET', KEYS[blocked] .. ':notice', '1', 'EX', retry, 'NX') return {blocked, retry, notice and 1 or 0} end for i, key in ipairs(KEYS) do local offset = (i - 1) * 3 if values[i] == 0 then redis.call('SET', key, ARGV[offset + 3], 'EX', ARGV[offset + 2]) else redis.call('INCRBY', key, ARGV[offset + 3]) end end return {0, 0, 0} LUA; /** @param array $buckets */ public function consume(array $buckets): array { $keys = array_column($buckets, 'key'); $arguments = []; foreach ($buckets as $bucket) { if ($bucket['limit'] < 1 || $bucket['seconds'] < 1 || $bucket['cost'] < 1 || $bucket['cost'] > $bucket['limit']) { throw new \LogicException('Invalid protection quota configuration'); } array_push($arguments, $bucket['limit'], $bucket['seconds'], $bucket['cost']); } return Redis::connection(config('mini_protection.connection', 'default')) ->eval(self::SCRIPT, count($keys), ...array_merge($keys, $arguments)); } }