*/ protected $sentinels; /** * Create a new PhpRedis Sentinel connection. * * @param \RedisCachePro\Configuration\Configuration $config */ public function __construct(Configuration $config) { $this->config = $config; foreach ($config->sentinels as $sentinel) { $this->sentinels[$sentinel] = null; } $this->connectToSentinels(); } /** * Establish a connection to the given Redis Sentinel and its primary and replicas. * * @param string $url * @return void */ protected function establishConnections(string $url) { $version = (string) \phpversion('redis'); $config = clone $this->config; $config->setUrl($url); $persistentId = ''; $arguments = [ 'host' => $config->host, 'port' => $config->port, 'connectTimeout' => $config->timeout, 'persistent' => $persistentId, 'retryInterval' => $config->retry_interval, 'readTimeout' => $config->read_timeout, ]; if ($config->password) { $arguments['auth'] = $config->username ? [$config->username, $config->password] : $config->password; } if ($config->tls_options && version_compare($version, '6.0', '>=')) { $arguments['ssl'] = $config->tls_options; } $this->sentinels[$url] = new PhpRedisSentinel(function () use ($arguments, $version) { return version_compare($version, '6.0', '<') ? new RedisSentinel(...array_values($arguments)) : new RedisSentinel($arguments); }, $config->tracer); $this->discoverPrimary(); $this->discoverReplicas(); } /** * Discovers and connects to the Sentinel primary. * * @return void */ protected function discoverPrimary() { $primary = $this->sentinel()->getMasterAddrByName($this->config->service); if (! $primary) { throw new ConnectionException("Failed to retrieve sentinel primary of `{$this->sentinel}`"); } $config = clone $this->config; $config->setHost($primary[0]); $config->setPort($primary[1]); $connection = PhpRedisConnector::connectToInstance($config); /** @var array $role */ $role = $connection->role(); if (($role[0] ?? null) !== 'master') { throw new ConnectionException("Sentinel primary of `{$this->sentinel}` is not a primary"); } $this->primary = $connection; } /** * Discovers and connects to the Sentinel replicas. * * @return void */ protected function discoverReplicas() { $replicas = $this->sentinel()->slaves($this->config->service); if (! $replicas) { throw new ConnectionException("Failed to discover Sentinel replicas of `{$this->sentinel}`"); } $this->replicas = []; foreach ($replicas as $replica) { if (($replica['role-reported'] ?? '') !== 'slave') { continue; } $config = clone $this->config; $config->setHost($replica['ip']); $config->setPort($replica['port']); try { $this->replicas[$replica['name']] = PhpRedisConnector::connectToInstance($config); } catch (Throwable $error) { if ($this->config->debug) { error_log("objectcache.notice: {$error->getMessage()}"); } } } } /** * Returns the current Sentinel connection. * * @return \RedisCachePro\Clients\PhpRedisSentinel */ public function sentinel() { return $this->sentinels[$this->sentinel]; } }