ClickHouseClickHouse для TrueAsync: пул соединений

Пул соединений ​

Каждый Client владеет скрытым пулом соединений «по корутине». Вы никогда не создаёте его и не управляете им напрямую. query, insert и insertBatch забирают физическое соединение в начале и возвращают его по завершении (стримящийся результат query() удерживает соединение, пока не будет прочитан полностью).

Зачем «по корутине» ​

Конкурентные корутины не должны делить один сокет; их чтения и записи переплелись бы на проводе. Поэтому каждая корутина, выполняющая запрос, получает своё соединение из пула, и несколько запросов могут быть в полёте одновременно:

php
use function Async\spawn;
use function Async\await_all;

$client = new Client(['host' => '127.0.0.1']);

// Эти три выполняются конкурентно, каждый на своём соединении из пула.
[$results] = await_all([
    spawn(fn() => $client->query("SELECT sleep(1), 1 AS n")->fetchAll()),
    spawn(fn() => $client->query("SELECT sleep(1), 2 AS n")->fetchAll()),
    spawn(fn() => $client->query("SELECT sleep(1), 3 AS n")->fetchAll()),
]);

Размер ​

'pool' => ['max' => N] (по умолчанию 10) ограничивает число физических соединений. Когда все max заняты, следующий запросивший ждёт, пока одно освободится. Соединения создаются лениво, по требованию.

Обработка сбоев ​

Соединение, умершее посреди операции (сброс пира, таймаут, ошибка протокола), помечается сломанным и уничтожается, а не возвращается в пул. Следующий запрос прозрачно получает свежее, здоровое соединение, поэтому одно оборванное соединение не всплывает дважды.

getPool(): \Async\Pool ​

Для продвинутых нужд getPool() возвращает нижележащую обёртку TrueAsync Async\Pool:

php
$pool = $client->getPool();

$pool->count();        // всего соединений
$pool->idleCount();    // простаивающие (доступные)
$pool->activeCount();  // в работе

$pool->getState();     // состояние circuit breaker
$pool->close();        // закрыть пул

Это запасной механизм (escape hatch); при обычном использовании вы к нему не прикасаетесь. Поверхность — стандартная обёртка пула TrueAsync (статистика, circuit breaker, жизненный цикл, ручные acquire/tryAcquire/release).

Обёртка действительна, только пока жив владеющий Client: уничтожение Client закрывает пул, поэтому обёртка, сохранённая после этого момента, ссылается на закрытый пул.