Когда фикс есть, а проблема остается

Анатолий Разумовский
Два воркера разбирают одну очередь: один на новом коде, другой на старом

Как-то раз мне пришлось разбираться с проблемой, которая поначалу выглядела как ошметок самой настоящей черной магии. Хотя по итогу это оказалось очень простым и логичным поведением системы, отловить его получилось далеко не сразу.

Для понимания контекста расскажу немного о проекте. На тот момент в команде было всего несколько разработчиков. Сам проект был написан на PHP с достаточно большой кодовой базой. Местами бизнес-логика была довольно сложной, поэтому активно использовались очереди. Драйвером очередей выступала база данных — то есть консьюмеры очередей работали прямо через БД (это один из стандартных драйверов). Очень простое решение «из коробки», которое обычно ставят на старте, чтобы не раздувать стек. Частенько оно так и остается надолго, если нет необходимости масштабировать проект.

И вот в какой-то момент в самом сердце проекта (воронке продаж) обнаружился неприятный баг. В некоторых случаях он ломал процесс оплаты, поэтому фиксить его нужно было максимально срочно.

Сам по себе баг был не особо сложным, так что проблему я решил быстро и задеплоил правки на тестовый стенд. Однако, к моему удивлению, прогнав несколько тестов, я заметил, что баг никуда не делся — хоть и стал проявляться немного реже. Это стало большим сюрпризом: локально проблема больше не воспроизводилась (да-да, «на моем компьютере все работает!»), а вот в тестовой среде все было далеко не так гладко.

Перепроверив все в деталях, я был на 100% уверен, что проблема решена. Убедился, что CI/CD прошел корректно, кодовая база и контейнеры на сервере актуальные… Но и баг тоже остался актуальным.

Тут можно сделать паузу и подумать, в чем же все-таки было дело. Или просто заглянуть под спойлер. У меня эта пауза затянулась примерно на четыре часа дебага и попыток понять, что вообще происходит.

Спойлер

Оказалось, что один из разработчиков подключил базу тестового стенда к своему локальному окружению. На его компьютере проект был запущен со старым кодом. В итоге его локальные консьюмеры время от времени перехватывали задачи из общей очереди и выполняли их по старой логике — без моих обновлений.

По итогу можно было бы просто забрать у всех прямой доступ к базе, но это сильно ударило бы по удобству разработки. Поэтому я перевел очереди на Redis (который не торчит наружу) — и проблема была решена.

Вот такая она, командная разработка…