
Postgres advisory locks на Neon ломаются от TCP-сброса. История четырёх фиксов retry-логики
MatushkinVD 9 минут назад Postgres advisory locks на Neon ломаются от TCP-сброса. История четырёх фиксов retry-логики Уровень сложности Средний Время на прочтение 12 мин Охват и читатели 203 PostgreSQL * Node.JS *...
Anthropic — What company has the best second artificial intelligence model at the end of June?
В сфере искусственного интеллекта произошло заметное событие. MatushkinVD 9 минут назад Postgres advisory locks на Neon ломаются от TCP-сброса. История четырёх фиксов retry-логики Уровень сложности Средний Время на прочтение 12 мин Охват и читатели 203 PostgreSQL * Node. JS * Высоконагруженные системы * Распределённые системы * Программирование * Ретроспектива Расскажу про четыре production-инцидента на одном куске кода за десять дней.
В каждом я думал, что разобрался. Закончилось тем, что я выкинул pg_advisory_lock из retry-пути и поставил FOR UPDATE SKIP LOCKED . Day-generation лок остался advisory-ным, но утечка там не критична - почему именно, разберу в конце.
Технические детали
Полезно, если у вас Postgres на Neon (или Supabase, или Aiven serverless) и где-то по коду есть session-scoped advisory locks для координации задач между репликами. Контекст В моём пет-проекте автоматический генератор контента: cron каждые 6 часов вызывает generateDailyBlogPost() . Сама функция читается несложно: Проверяет, нет ли уже поста за сегодня ( hasTodayPost() ).
Если нет, обращается к 5 LLM, выбирает тип контента по дню недели, склеивает статью, делает INSERT INTO blog_posts с published = TRUE . Переводит на английский (Gemini Flash Lite), постит в Telegraph, в два TG-канала (RU/EN), в стену VK-сообщества. Координация между потенциально дублирующимися репликами (Railway во время деплоя на минуту крутит и старый, и новый инстанс) держится на pg_advisory_lock с ключом, рассчитанным от номера UTC-дня.
Идея учебниковая: первый, кто захватил лок, генерирует, остальные видят lock_held и выходят. База у меня живёт в Neon - это serverless Postgres, который масштабируется в обе стороны и активно сбрасывает простаивающие соединения. Это будет важно по ходу.
Отраслевые последствия
23 апреля начало падать. Итерация 1 (23 апреля): lock_held пропускал retry целиком Утром 23-го RU-пост в TG-канал ушёл, а EN не ушёл. В БД обе записи на месте, обе published = TRUE .
У RU-поста channel_posted_at стоит, у EN-поста NULL . Пост создан, но публикация в канал не докатилась. Полез в логи Railway.
На одной из реплик было: generation lock held, skipping returning lock_held generateDailyBlogPost возвращал lock_held и сразу выходил. А retry-логика для пропавших публикаций ( retryTodayChannelPosts ) вызывалась только во внутренней функции _generateDailyBlogPostInner после ветки "пост уже существует" - а значит, retry никогда не запускался, если другая реплика уже держала лок. Сценарий получался такой: реплика A заинсертила пост, но упала на TG (или VK завис на 30 секунд, или Telegraph вернул 504, что угодно).
Этот прогресс даёт важные сигналы о будущем отрасли, и технологический мир внимательно наблюдает.





