Привет! Спасибо за подробный разбор. Такой комментарий действительно полезен: по обычному демо в браузере часть подобных проблем легко не заметить, а при чтении кода они становятся видны сразу.
По нескольким пунктам я с вами согласен.
Замечание про N+1 в уведомлениях при обновлении профиля справедливое. В старом варианте логика действительно могла идти через цепочку “найти чаты пользователя → для каждого чата найти участников → для каждого участника найти пользователя → отправить событие”. Для небольшого демо это незаметно, но как паттерн для роста нагрузки такой подход неудачный.
То же самое с markChatAsRead(). В исходном варианте метод делал слишком много за один вызов: получал список сообщений, проходил по ним в цикле, обновлял receipt/status и отправлял отдельные события. На длинной истории это действительно плохой путь, особенно если чат активно используется.
После вашего комментария я отдельно прошёлся по backend и переработал эти участки.
Что было изменено:
— уведомления при обновлении профиля и обновлении списка чатов переведены на batch-запросы и отправку по уникальным получателям; — mark read / mark delivered переписаны через bulk SQL-операции вместо поштучного прохода по сообщениям; — вместо множества отдельных status events добавлен bulk status event; — timeline reactions теперь грузятся пачкой, без N+1 на каждое сообщение; — список чатов получил пагинацию и сортировку ближе к БД; — часть логики вынесена из контроллеров в сервисы; — Map<String, Object> в ключевых REST-ответах заменён на typed DTO; — добавлены индексы под горячие запросы через миграцию V23__performance_indexes.sql; — после рефакторинга обновлены тесты.
Что было → стало
Отдельно прогнал тесты и нагрузочные сценарии по direct-chat path. Backend сейчас проходит 192 теста. По k6 direct-chat battery получилось:
Суммарно по direct-chat battery:
Самым важным результатом для меня было не просто отсутствие ошибок, а то, что mark read / mark delivered не начали деградировать на длинном прогоне. В 30-минутном soak:
При этом я не хочу выдавать эти результаты за полную production-готовность. Это пока проверка именно direct-chat HTTP/API-сценария. Групповые чаты, WebSocket load, сценарии с заранее набитыми 10k+ сообщений, поведение БД на больших объёмах и инфраструктурные лимиты ещё нужно проверять отдельно.
Поэтому я бы сейчас аккуратно сформулировал статус проекта так: это не production-ready мессенджер, но уже рабочий MVP/pet project, который постепенно приводится к более зрелому backend-состоянию.
Ваш комментарий помог подсветить места, которые на обычном демо не бросались в глаза. Спасибо за это. Если будет желание — буду рад продолжить предметно по query patterns, pagination strategy, receipt aggregation и group chat fanout.
Чем ближе закат империи, тем безумнее её законы.
Дополнительно проверили WebSocket‑часть: на локальном стенде соединения держатся стабильно, а предел дальше упирается уже в ресурсы машины.
Привет! Спасибо за подробный разбор. Такой комментарий действительно полезен: по обычному демо в браузере часть подобных проблем легко не заметить, а при чтении кода они становятся видны сразу.
По нескольким пунктам я с вами согласен.
Замечание про N+1 в уведомлениях при обновлении профиля справедливое. В старом варианте логика действительно могла идти через цепочку “найти чаты пользователя → для каждого чата найти участников → для каждого участника найти пользователя → отправить событие”. Для небольшого демо это незаметно, но как паттерн для роста нагрузки такой подход неудачный.
То же самое с
markChatAsRead(). В исходном варианте метод делал слишком много за один вызов: получал список сообщений, проходил по ним в цикле, обновлял receipt/status и отправлял отдельные события. На длинной истории это действительно плохой путь, особенно если чат активно используется.После вашего комментария я отдельно прошёлся по backend и переработал эти участки.
Что было изменено:
— уведомления при обновлении профиля и обновлении списка чатов переведены на batch-запросы и отправку по уникальным получателям;
—
mark read/mark deliveredпереписаны через bulk SQL-операции вместо поштучного прохода по сообщениям;— вместо множества отдельных status events добавлен bulk status event;
— timeline reactions теперь грузятся пачкой, без N+1 на каждое сообщение;
— список чатов получил пагинацию и сортировку ближе к БД;
— часть логики вынесена из контроллеров в сервисы;
—
Map<String, Object>в ключевых REST-ответах заменён на typed DTO;— добавлены индексы под горячие запросы через миграцию
V23__performance_indexes.sql;— после рефакторинга обновлены тесты.
Отдельно прогнал тесты и нагрузочные сценарии по direct-chat path. Backend сейчас проходит 192 теста. По k6 direct-chat battery получилось:
Самым важным результатом для меня было не просто отсутствие ошибок, а то, что
mark read/mark deliveredне начали деградировать на длинном прогоне. В 30-минутном soak:При этом я не хочу выдавать эти результаты за полную production-готовность. Это пока проверка именно direct-chat HTTP/API-сценария. Групповые чаты, WebSocket load, сценарии с заранее набитыми 10k+ сообщений, поведение БД на больших объёмах и инфраструктурные лимиты ещё нужно проверять отдельно.
Поэтому я бы сейчас аккуратно сформулировал статус проекта так: это не production-ready мессенджер, но уже рабочий MVP/pet project, который постепенно приводится к более зрелому backend-состоянию.
Ваш комментарий помог подсветить места, которые на обычном демо не бросались в глаза. Спасибо за это. Если будет желание — буду рад продолжить предметно по query patterns, pagination strategy, receipt aggregation и group chat fanout.
█████████████████████████████████▶ 75% начинаю удаление репозитория…
Спасибо!