13.5. Обработка сбоев сериализации

На уровнях изоляции Repeatable Read и Serializable могут выдаваться ошибки с целью предотвращения аномалий сериализации. Как отмечалось ранее, приложения, использующие эти уровни, должны быть готовы повторить транзакции, завершившиеся сбоем из-за ошибок сериализации. Текст такого сообщения об ошибке может варьироваться в зависимости от конкретных обстоятельств, но код SQLSTATE всегда будет 40001 (serialization_failure).

Также может иметь смысл повторять запросы в случае ошибок взаимоблокировки. Такие ошибки имеют код SQLSTATE 40P01 (deadlock_detected).

В некоторых случаях также целесообразно повторять запросы после ошибок уникальности ключа, которые имеют код SQLSTATE 23505 (unique_violation), и ошибок нарушения исключения, которые имеют код SQLSTATE 23P01 (exclusion_violation). Например, если приложение выбирает новое значение для столбца первичного ключа, предварительно выяснив, какие значения уже есть, оно может столкнуться с ошибкой уникальности ключа, потому что другой экземпляр этого же приложения одновременно выбрал то же значение. По сути, это ошибка сериализации, но сервер не обнаруживает её как таковую, потому что он не может «видеть» связь между добавляемым значением и предыдущим чтением. Есть также некоторые особые случаи, когда сервер выдаёт ошибку уникального ключа или нарушения исключения, даже если у него в принципе достаточно информации, чтобы определить, что основной причиной является проблема сериализации. Тогда как запросы, вызвавшие ошибки serialization_failure, рекомендуется просто повторять, это не распространяется на запросы, завершающиеся ошибками с другими кодами, поскольку такие ошибки могут свидетельствовать о постоянных проблемах, а не о временных сбоях.

Повторять транзакцию важно целиком, включая всю логику, которая решает, какой SQL выдавать и/или какие значения использовать. Postgres Pro не предлагает средства автоматического повторения запросов, так как не может гарантировать их правильность.

Повторение транзакции не гарантирует, что такая транзакция будет завершена успешно; может потребоваться несколько повторных попыток. Когда уровень конкуренции очень высок, для успешного выполнения транзакции может потребоваться много попыток. В случаях, когда конфликт связан с подготовленной транзакцией, разрешить конфликт может быть невозможно, пока подготовленная транзакция не будет зафиксирована или отменена.

13.5. Serialization Failure Handling

Both Repeatable Read and Serializable isolation levels can produce errors that are designed to prevent serialization anomalies. As previously stated, applications using these levels must be prepared to retry transactions that fail due to serialization errors. Such an error's message text will vary according to the precise circumstances, but it will always have the SQLSTATE code 40001 (serialization_failure).

It may also be advisable to retry deadlock failures. These have the SQLSTATE code 40P01 (deadlock_detected).

In some cases it is also appropriate to retry unique-key failures, which have SQLSTATE code 23505 (unique_violation), and exclusion constraint failures, which have SQLSTATE code 23P01 (exclusion_violation). For example, if the application selects a new value for a primary key column after inspecting the currently stored keys, it could get a unique-key failure because another application instance selected the same new key concurrently. This is effectively a serialization failure, but the server will not detect it as such because it cannot see the connection between the inserted value and the previous reads. There are also some corner cases in which the server will issue a unique-key or exclusion constraint error even though in principle it has enough information to determine that a serialization problem is the underlying cause. While it's recommendable to just retry serialization_failure errors unconditionally, more care is needed when retrying these other error codes, since they might represent persistent error conditions rather than transient failures.

It is important to retry the complete transaction, including all logic that decides which SQL to issue and/or which values to use. Therefore, Postgres Pro does not offer an automatic retry facility, since it cannot do so with any guarantee of correctness.

Transaction retry does not guarantee that the retried transaction will complete; multiple retries may be needed. In cases with very high contention, it is possible that completion of a transaction may take many attempts. In cases involving a conflicting prepared transaction, it may not be possible to make progress until the prepared transaction commits or rolls back.

FAQ