Итак, у меня есть онлайн-игра на PHP / PostgreSQL, и один из процессов обновления иногда дает мне тупики, например:
[2016-02-16 06:35:14] app.ERROR: Doctrine \ DBAL \ DBALException: An
возникла исключительная ситуация при выполнении ‘UPDATE PlayerCharacter SET
spotting_distance =?, видимость =? ГДЕ id =? ‘ с параметрами [2167,
20, 128]: SQLSTATE [40P01]: обнаружена взаимоблокировка: 7 ОШИБКА: взаимоблокировка
обнаружена ДЕТАЛИ: Процесс 11691 ожидает ShareLock в транзакции
4173974; заблокирован процессом 11706. Процесс 11706 ожидает ShareLock
по транзакции 4173977; заблокирован процессом 11691. Подсказка: см. сервер
журнал для деталей запроса.
Я попытался просмотреть журналы сервера, но это не помогает.
Проблема в том, что я понятия не имею, как это происходит, потому что, хотя я вижу точную строку в коде, который его вызывает, я не понимаю, как это происходит.
Код обновляет большое количество строк, поэтому я разделил обработку на 6 параллельных процессов, каждый из которых обновляет подмножество общего количества. Другими словами: никакой другой процесс не должен обновлять строку первичным идентификатором 128. Так почему же существует тупик?
Я подозреваю, что а) что-то странное или б) ошибка в моем коде планирования и какой-то другой процесс является обновление строки № 128.
Как я могу узнать, что происходит? Могу ли я убедить Doctrine или Postgres показать мне блокирующую транзакцию? Можно ли как-то сделать транзакцию неблокируемой (поскольку это параллельные процессы, использующие одну и ту же математику, результат должен быть одинаковым в любом случае, и если по какой-то причине это не так, я бы предпочел получить результат, который будет несколько процентов, чем тупик).
Задача ещё не решена.
Других решений пока нет …