File: //proc/1122/cwd/common/components/TelegramRateLimiter.php
<?php
namespace common\components;
use yii\base\Component;
use yii\di\Instance;
use yii\redis\Connection;
/**
* Global Telegram send rate per bot: max $maxPerSecond requests per rolling 1s window (Redis ZSET).
*/
class TelegramRateLimiter extends Component
{
public $redis = 'redis';
/** @var int max API calls per second (Telegram global ~30; we use 25) */
public $maxPerSecond = 25;
/** @var float window seconds */
public $windowSeconds = 1.0;
public function init(): void
{
parent::init();
$this->redis = Instance::ensure($this->redis, Connection::class);
}
public function acquire(int $botId): void
{
while (!$this->tryAcquire($botId)) {
sleep(1);
}
}
public function tryAcquire(int $botId): bool
{
$key = 'tg:rl:' . $botId;
$now = microtime(true);
$windowStart = $now - $this->windowSeconds;
$member = uniqid('m', true);
/** @var Connection $redis */
$redis = $this->redis;
$redis->executeCommand('ZREMRANGEBYSCORE', [$key, (string) 0, (string) $windowStart]);
$n = (int) $redis->executeCommand('ZCARD', [$key]);
if ($n >= $this->maxPerSecond) {
return false;
}
$redis->executeCommand('ZADD', [$key, (string) $now, $member]);
$redis->executeCommand('EXPIRE', [$key, (string) 3]);
return true;
}
}