Клиент пришёл за техническим аудитом

Часть пользовательских операций выполнялась слишком долго или не завершалась корректно. Особенно это касалось удаления и копирования данных.

Если процесс обрывался, система теряла целостность: что-то уже удалено, а что-то ещё нет. Для проекта с 10 000+ пользователей это означало нестабильность в критичных сценариях.

Асинхронность только спрятала сбой

Команда пыталась вынести операции в асинхронный режим. Внешне это выглядело как улучшение: пользователь меньше ждал и реже видел ошибку. Но причина осталась.

  • пользователь не понимал, что операция выполнилась не до конца;
  • система вела себя непредсказуемо;
  • ошибки становились тише, но не исчезали.

Узкое место было в самой структуре операции

  • 20 000+ SQL-запросов на одну операцию;
  • последовательные каскадные удаления вместо пакетной работы;
  • критичные связи без нужных индексов;
  • линейная деградация при росте объёма данных;
  • дополнительные задержки из-за вызовов внешних API.

Стало ясно: проблема не в том, что процесс синхронный или асинхронный, а в том, как построен сценарий и как устроены связи данных.

Я предложил разделить сценарии и убрать лишнюю работу

  1. разделить простые и глубокие сценарии удаления;
  2. использовать пакетные операции там, где это безопасно;
  3. сократить число запросов до нескольких вместо тысяч;
  4. добавить индексацию на критических связях;
  5. оставить каскад только там, где он реально нужен;
  6. использовать асинхронность как инструмент, а не как маскировку дефекта.

Система стала предсказуемой

После внедрения командой операции перестали зависеть от объёма данных и больше не создавали скрытых ошибок.

  • время выполнения сократилось с 10+ минут до примерно 3 секунд;
  • количество запросов упало с 20 000+ до нескольких;
  • поведение под нагрузкой стало стабильным;
  • пользователь перестал сталкиваться с «тихими» сбоями.

Если одна операция кладёт систему, проблема в архитектуре

Асинхронность полезна, когда сценарий уже спроектирован правильно. Если она нужна только затем, чтобы скрыть перегруженную операцию, это сигнал пересмотреть структуру данных и сам процесс.