Приходилось ли менять уровни изоляции транзакций?
Что проверяют
Понимаете ли вы аномалии и уровни, и, что важнее для Node.js, умеете ли держать транзакцию на одном соединении. Пул и асинхронность дают здесь ошибку, которой в синхронных языках просто нет.
Как отвечать
Назовите аномалии: грязное чтение, неповторяющееся чтение, фантомы, аномалия сериализации. Потом привяжите к базе. В PostgreSQL по умолчанию READ COMMITTED, грязного чтения не бывает вообще, REPEATABLE READ работает как снимок, а при конфликте отдаёт ошибку с кодом 40001, которую надо ловить и повторять транзакцию целиком.
Технику покажите на своём стеке:
const client = await pool.connect();
try {
await client.query("BEGIN ISOLATION LEVEL REPEATABLE READ");
// все запросы транзакции идут только через client
await client.query("COMMIT");
} catch (e) {
await client.query("ROLLBACK");
throw e;
} finally {
client.release();
}В ORM уровень задаётся параметром транзакции. Добавьте, что у интерактивной транзакции есть таймаут, и обращение к внешнему сервису внутри неё этот таймаут выбирает, попутно удерживая соединение из пула.
Где спотыкаются
Ведут транзакцию через пул, а не через один клиент. BEGIN уходит в одно соединение, UPDATE в другое, и транзакции фактически нет. Рядом живёт вторая беда: release() не в блоке finally, соединения утекают, и пул однажды заканчивается.
Повышают уровень и не делают повтор. С REPEATABLE READ и выше ошибка сериализации это штатная ситуация, а не сбой, и без цикла повторов вы меняете редкую гонку на регулярные ошибки у пользователей.
Лечат изоляцией то, что лечится запросом. Классика: прочитали значение, посчитали новое в JavaScript, записали обратно. Между чтением и записью успевает вклиниться чужая правка, и никакой уровень не спасёт, пока обновление не станет атомарным или не появится проверка версии строки.