Есть ли лучший способ проверить состояние подключения и при необходимости повторно подключиться? #
Да, по крайней мере, на мой взгляд, потому что есть только один подход, свободный от условий гонки, и это выполнение запроса в цикле повтора, который обрабатывает ошибки, если они возникают.
В противном случае у вас все еще есть:
PREPARE
SELECT 1;
или как там написано в вашем тестовом заявлении
- Отключение сети, сбой серверной части, администратор перезагружает сервер и т. Д.
EXECUTE
- splat.
Для правильного поведения требуется что-то вроде псевдокода:
while not succeeded:
try:
execute_statement()
succeeded = True
except some_database_exception:
if transaction_is_valid():
// a `SELECT 1` or `select 1 from pg_prepared_statements where name = 'blah'
// succeeded in transaction_is_valid(), so the issue was probably
// transient. Retry, possibly with a retry counter that resets the
// connection if more than a certain number of retries.
// It can also be useful to examine the exception or error state to
// see if the error is recoverable so you don't do things like retry
// repeatedly for a transaction that's in the error state.
else if test_connection_usable_after_rollback():
// Connection is OK but transaction is invalid. You might determine
// this from the exception state or by seeing if sending a `ROLLBACK`
// succeeds. In this case you don't have to re-prepare, just open
// a new transaction. This case is not needed if you're using autocommit.
else:
// If you tried a SELECT 1; and a ROLLBACK and neither succeeded, or
// the exception state suggests the connection is dead. Re-establish
// it, re-prepare, and restart the last transaction from the beginning.
reset_connection_and_re_prepare()
Многословно и надоедливо? Да, но обычно легко обернуть в помощник или библиотеку. Все остальное по-прежнему подлежит гонкам.
Что наиболее важно, если ваше приложение выдает транзакции, в которых оно выполняет более одного действия, ему необходимо помнить все, что оно делало, до тех пор, пока транзакция не будет зафиксирована, и иметь возможность повторить всю транзакцию в случае ошибки. Это, или скажите пользователю «ой, я съел ваши данные, пожалуйста, введите их еще раз и попробуйте еще раз».
Если вы не возражаете против гонок и просто хотите обрабатывать любые явно мертвые соединения с помощью периодической проверки, просто сохраните время последнего запроса в переменной. При выполнении запросов проверьте, не старше ли отметка времени несколько минут, и если это так, выполните SELECT 1;
или запрос к pg_prepared_statements
, чтобы проверить подготовленный вами оператор. Вам нужно либо быть готовым к предупреждению об ошибках у пользователя, либо в любом случае обернуть все это в надлежащую обработку ошибок ... в этом случае нет никакого смысла вообще беспокоиться о проверке времени и тестировании.
person
Craig Ringer
schedule
31.08.2012