
Финальное подтверждение покупки происходит после сверки лога проведенных транзакций, периодически получаемых от платежного сервиса. Код в этом компоненте написан очень давно, покрыт тестами по самое "не балуйся" и не менялся уже больше года. Соответственно, теоретическое подозрение пало на изменение API платежной системы. Поход в централизованное хранилище логов показал, что ошибок обработки в этом компоненте не было за все время вообще. И тут я заметил, что после определенного момента сообщения в логах о запросе свежих транзакций пропадают. Как будто компонент упал и прекратил свою работу. Но такого не может быть, потому что он действует в рамках того-же процесса и просто запускается по расписанию в отдельном пуле потоков. После рестарта сервиса все заработало снова отлично.
И тут я вспомнил старую "страшилку" для Java разработчиков, пишущих микросервисы на Spring Boot. Она касается настройки таймаутов, которые использует автоматически создаваемый RestTemplate для установки соединения и чтения данных. Он берет их из ClientHttpRequestFactory, реализация по умолчанию которого SimpleClientHttpRequestFactory позволяет их настроить. А если не настроил, то действуют параметры по умолчанию для всей JVM, которые могут задаваться при старте JVM или снова таки будут иметь значения по умолчанию. А вот эти самые значения по умолчанию установлены в "нет таймаута". То есть, если у вас "зависает" соединение с внешним сервисом, то вы "висите" до перезапуска JVM. Что и произошло в моем случае.
Новый тест подтвердил предположение. Я в данном случае понадеялся на отслеживание зависших соединений на стороне платежной системы, а они, видимо, понадеялись на клиентов API. :) Выводы и действия:
- в распределенной системе на границах сетевого взаимодействия нужно быть готовым к любым проявлениям проблем;
- ключевые элементы лучше настраивать руками, в данном случае сконфигурировать бин с использованием RestTemplateBuilder, что и было сделано;
- каждое соединение между сервисами нужно обкладывать мониторингом, чтобы такие проблемы быстро обнаруживались, в данном примере это время последней синхронизации транзакций с платежной системой;
- чем больше правил вынесено в статические анализаторы, тем меньше вероятность допустить ошибку, но в данном случае не так просто настроить подобную проверку из-за "магии" Spring Boot.
Учитесь на чужих ошибках и верьте в "страшилки"! 😄
#java #resttemplate #distributed_systems
