Как проверить ошибку PG :: QueryCanceled (из-за тайм-аута) в приложении Rails? - PullRequest
0 голосов
/ 24 сентября 2018

На рабочем сервере я получил эту ошибку

ActiveRecord::StatementInvalid: PG::QueryCanceled: ERROR: canceling statement due to statement timeout <SQL query here>

В этой строке:

Contact.where(id: contact_ids_to_delete).delete_all

Запрос SQL был командой DELETE с огромным списком идентификаторов.Время истекло.Я пришел к решению, которое заключается в удалении контактов в пакетном режиме:

Contact.where(id: contact_ids_to_delete).in_batches.delete_all

Вопрос в том, как проверить мое решение?Или как обычно это проверить?Или есть какой-нибудь драгоценный камень, который сделал бы его удобным?
Я вижу два возможных способа его проверки:
1. (Динамически) установить тайм-аут в тестовой базе данных на небольшое количество секунд и создать тест, в котором я создаю много контактов, а затем пытаюсь запустить мойкод для их удаления.
Кажется, это правильный способ сделать это, но он может потенциально замедлить выполнение тестов, и динамическая установка таймаута (что было бы идеальным способом сделать это) может быть сложной.
2. Проверьте, что удаления в пакетном режиме.
Это может быть сложно, потому что таким образом мне придется отслеживать запросы.

1 Ответ

0 голосов
/ 24 сентября 2018

Это не крайний случай, который я бы протестировал, потому что он требует построения и выполнения запроса, который превышает встроенные тайм-ауты вашей базы данных;минимальное время выполнения для этого одиночного теста должно быть не меньше этого времени.

Даже в этом случае вы можете написать тест, который проходит 100% времени в вашей среде test, но не проходит 100% времени.в production из-за различий между двумя средами, которые вы никогда не сможете полностью воспроизвести;Например, ваша тестовая база данных используется одним и тем же пользователем, в то время как ваша производственная база данных будет иметь несколько одновременно работающих пользователей, разные доступные ресурсы и разные активные блокировки.Это не та проблема, для которой вы пишете тест, потому что тест не гарантирует, что он не произойдет в рабочей среде.Лучшие практики будут делать это.

Я рекомендую вам следовать рекомендациям для Rails , используя методы find_in_batches или find_each, ожидая, что сервер базы данных сможет успешно действоватьПакеты из 1000 записей одновременно:

Contact.where(id: contact_ids_to_delete).find_in_batches do |contacts|
  contacts.delete_all
end

Или, если вы предпочитаете:

Contact.where(id: contact_ids_to_delete).find_in_batches(&:delete_all)

Вы можете настроить размер пакета с помощью batch_size, если вы параноидально относитесь к своей производственной базе данныхсервер не может работать с 1000 записями одновременно:

Contact.where(id: contact_ids_to_delete).find_in_batches(batch_size: 500) { |contacts| contacts.delete_all }
...