Lookup: reconnections
This commit is contained in:
@ -38,9 +38,12 @@ abstract class Connection
|
|||||||
private $onCloseCallback;
|
private $onCloseCallback;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private string $address,
|
/**
|
||||||
private ClientConfig $clientConfig,
|
* @readonly
|
||||||
private LoggerInterface $logger,
|
*/
|
||||||
|
public string $address,
|
||||||
|
protected ClientConfig $clientConfig,
|
||||||
|
protected LoggerInterface $logger,
|
||||||
) {
|
) {
|
||||||
$this->stream = new NullStream();
|
$this->stream = new NullStream();
|
||||||
$this->onConnectCallback = static function () {
|
$this->onConnectCallback = static function () {
|
||||||
|
@ -25,17 +25,23 @@ final class Consumer extends Connection
|
|||||||
private $onMessage;
|
private $onMessage;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private string $address,
|
string $address,
|
||||||
private string $topic,
|
/**
|
||||||
private string $channel,
|
* @readonly
|
||||||
|
*/
|
||||||
|
public string $topic,
|
||||||
|
/**
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
public string $channel,
|
||||||
callable $onMessage,
|
callable $onMessage,
|
||||||
private ClientConfig $clientConfig,
|
ClientConfig $clientConfig,
|
||||||
private LoggerInterface $logger,
|
LoggerInterface $logger,
|
||||||
) {
|
) {
|
||||||
parent::__construct(
|
parent::__construct(
|
||||||
$this->address,
|
$address,
|
||||||
$clientConfig,
|
$clientConfig,
|
||||||
$this->logger,
|
$logger,
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->onMessage = $onMessage;
|
$this->onMessage = $onMessage;
|
||||||
|
@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||||||
namespace Nsq;
|
namespace Nsq;
|
||||||
|
|
||||||
use Amp\Deferred;
|
use Amp\Deferred;
|
||||||
|
use Amp\Dns\DnsException;
|
||||||
use Amp\Http\Client\DelegateHttpClient;
|
use Amp\Http\Client\DelegateHttpClient;
|
||||||
use Amp\Http\Client\HttpClientBuilder;
|
use Amp\Http\Client\HttpClientBuilder;
|
||||||
use Amp\Http\Client\Request;
|
use Amp\Http\Client\Request;
|
||||||
@ -123,38 +124,30 @@ final class Lookup
|
|||||||
$producers = $this->producers[$topic] ??= new Deferred();
|
$producers = $this->producers[$topic] ??= new Deferred();
|
||||||
|
|
||||||
if ($producers instanceof Deferred) {
|
if ($producers instanceof Deferred) {
|
||||||
|
/** @var array<string, Lookup\Producer> $producers */
|
||||||
$producers = yield $producers->promise();
|
$producers = yield $producers->promise();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var \Nsq\Lookup\Producer $producer */
|
foreach (array_diff_key($consumers, $producers) as $address => $producer) {
|
||||||
foreach ($producers as $producer) {
|
unset($consumers[$address]);
|
||||||
$address = $producer->toTcpUri();
|
}
|
||||||
$consumerKey = $topic.$address;
|
|
||||||
|
|
||||||
if (\array_key_exists($consumerKey, $consumers)) {
|
foreach ($producers as $address => $producer) {
|
||||||
|
if (\array_key_exists($address, $consumers)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$promise = ($consumers[$consumerKey] = new Consumer(
|
$this->keepConnection(
|
||||||
|
new Consumer(
|
||||||
$address,
|
$address,
|
||||||
$topic,
|
$topic,
|
||||||
$channel,
|
$channel,
|
||||||
$onMessage,
|
$onMessage,
|
||||||
$config,
|
$config,
|
||||||
$this->logger,
|
$this->logger,
|
||||||
))->onClose(function () use ($consumerKey, &$consumers) {
|
),
|
||||||
unset($consumers[$consumerKey]);
|
$consumers,
|
||||||
})->connect();
|
);
|
||||||
|
|
||||||
$promise->onResolve(function (?\Throwable $e) use ($consumerKey, &$consumers) {
|
|
||||||
if (null !== $e) {
|
|
||||||
$this->logger->error($e->getMessage());
|
|
||||||
|
|
||||||
unset($consumers[$consumerKey]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
yield $promise;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
yield delay($this->config->pollingInterval);
|
yield delay($this->config->pollingInterval);
|
||||||
@ -183,6 +176,45 @@ final class Lookup
|
|||||||
$this->logger->info('Unsubscribed.', compact('topic', 'channel'));
|
$this->logger->info('Unsubscribed.', compact('topic', 'channel'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function keepConnection(Consumer $consumer, &$consumers): void
|
||||||
|
{
|
||||||
|
$consumers[$consumer->address] = $consumer;
|
||||||
|
|
||||||
|
asyncCall(function () use ($consumer, &$consumers) {
|
||||||
|
while (\array_key_exists($consumer->address, $consumers)) {
|
||||||
|
try {
|
||||||
|
yield $consumer->connect();
|
||||||
|
} catch (DnsException $e) {
|
||||||
|
$this->logger->error($e->getMessage(), ['exception' => $e]);
|
||||||
|
|
||||||
|
unset($consumers[$consumer->address], $this->producers[$consumer->topic][$consumer->address]);
|
||||||
|
|
||||||
|
return;
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
$this->logger->error($e->getMessage(), ['exception' => $e]);
|
||||||
|
|
||||||
|
yield delay($this->config->pollingInterval);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (!\array_key_exists($consumer->address, $consumers)) {
|
||||||
|
$consumer->close();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$consumer->isConnected()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield delay(500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private function watch(string $topic): void
|
private function watch(string $topic): void
|
||||||
{
|
{
|
||||||
if (\array_key_exists($topic, $this->topicWatchers)) {
|
if (\array_key_exists($topic, $this->topicWatchers)) {
|
||||||
@ -218,15 +250,14 @@ final class Lookup
|
|||||||
|
|
||||||
$producers = [];
|
$producers = [];
|
||||||
foreach ($responses as $response) {
|
foreach ($responses as $response) {
|
||||||
if (($deferred = ($this->producers[$topic] ?? null)) instanceof Deferred) {
|
|
||||||
$deferred->resolve($response->producers);
|
|
||||||
unset($this->producers[$topic]);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($response->producers as $producer) {
|
foreach ($response->producers as $producer) {
|
||||||
$producers[$producer->toTcpUri()] = $producer;
|
$producers[$producer->toTcpUri()] = $producer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (($deferred = ($this->producers[$topic] ?? null)) instanceof Deferred) {
|
||||||
|
$deferred->resolve($producers);
|
||||||
|
}
|
||||||
$this->producers[$topic] = $producers;
|
$this->producers[$topic] = $producers;
|
||||||
|
|
||||||
yield delay($this->config->pollingInterval);
|
yield delay($this->config->pollingInterval);
|
||||||
|
@ -16,14 +16,14 @@ use function Amp\call;
|
|||||||
final class Producer extends Connection
|
final class Producer extends Connection
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private string $address,
|
string $address,
|
||||||
private ClientConfig $clientConfig,
|
ClientConfig $clientConfig,
|
||||||
private LoggerInterface $logger,
|
LoggerInterface $logger,
|
||||||
) {
|
) {
|
||||||
parent::__construct(
|
parent::__construct(
|
||||||
$this->address,
|
$address,
|
||||||
$this->clientConfig,
|
$clientConfig,
|
||||||
$this->logger,
|
$logger,
|
||||||
);
|
);
|
||||||
|
|
||||||
$context = compact('address');
|
$context = compact('address');
|
||||||
|
Reference in New Issue
Block a user