Микросервисы на Go после основ: чему учиться на сбое между сервисами
Вы написали на Go API для бронирования места. Клиент отправил POST, подождал и получил таймаут. В базе бронь могла уже появиться, а ответ потерялся по дороге. Пользователь нажмёт кнопку ещё раз — что увидит сервис? Если он просто создаст вторую бронь, ошибка сети превратится в ошибку данных.
Именно с таких ситуаций начинается обучение взаимодействию сервисов. После основ Go полезно разбираться не по отдельности в названиях PostgreSQL, gRPC и Kafka, а в том, какое состояние останется после каждого шага и как восстановить работу.
Сначала отделите ошибку ответа от исхода операции
Для клиента таймаут означает только, что результат вовремя не получен. Он не говорит, дошёл ли запрос до сервера и завершилась ли запись в базу. Поэтому меняющему запросу нужен устойчивый идентификатор операции, например request_id, который клиент повторяет при новой попытке. Сервис должен найти уже выполненную операцию по этому идентификатору и вернуть её прежний результат; повтор с тем же ключом, но другим содержанием запроса следует отклонить. Уникальность ключа и запись брони защищают транзакцией и ограничениями базы: две одновременные попытки не должны создать два места.
Разбирая уроки, проследите три исхода: запрос не дошёл; бронь сохранилась, а ответ потерялся; повтор пришёл одновременно с первой попыткой. Они требуют разных наблюдений, но одного бизнес-правила — один request_id даёт один результат. HTTP-клиент Go позволяет задать время ожидания, однако сам таймаут не разрешает вопрос о состоянии удалённой базы.
Когда один сервис запрашивает данные у другого, передавайте ограничение времени дальше по цепочке. Иначе исходный клиент уже перестал ждать, а соседний сервис продолжает дорогой поиск. В Go исходящий HTTP-запрос можно связать с context входящего обращения; для gRPC программа тоже разбирает передачу deadline. При этом для важной операции нужно решить, где остановка допустима. Отмена ожидания ответа не должна стирать уже зафиксированную бронь и делать её невидимой для повтора.
Затем проверьте, что происходит после записи
Предположим, после брони надо отправить событие в другой сервис. Если сначала записать бронь в PostgreSQL, а затем попытаться отправить сообщение в Kafka, между действиями может произойти сбой. Бронь останется, а получатель о ней не узнает. Один из способов уменьшить этот разрыв — записать бронь и запись для отправки в одной транзакции базы. Отдельный процесс затем отправляет накопленные события. Это называют outbox.
Получатель тоже должен быть готов к повтору: сообщение может прийти ещё раз до подтверждения обработки. Он хранит идентификатор уже принятого события и не применяет изменение дважды; этот приём обычно называют inbox. Понимание этих двух шагов важнее умения запустить брокер одной командой. Спросите себя, какие записи остались в базе после сбоя и что повторит программа при следующем запуске.
После решения о доставке остаётся вопрос изменения контрактов. Один сервис может выйти раньше другого. Если новое поле в событии или ответе становится обязательным сразу, старый получатель перестанет понимать сообщения. В программе ищите сценарий, где старый и новый процессы работают рядом: какие поля можно добавить безопасно, как проверить старого клиента и когда удалить прежний формат. Это практический смысл независимого выпуска сервисов, а не только отдельные Docker-контейнеры.
Когда пора переходить к такой программе
Хорошая база для старта — функции, структуры, интерфейсы и обработка ошибок Go, простой HTTP-обработчик и запуск go test. Эти навыки позволяют следить за кодом, пока курс добавляет сетевой вызов и отдельное хранилище. Знание PostgreSQL, Kafka и gRPC до начала программы Latorn не требуется: темы входят в уроки. Если вы только учитесь разбирать JSON и возвращать HTTP-ошибки, сначала закрепите эти действия на небольшом API.
В курсе «Микросервисы на Go» вы начнёте с вызова другой программы и ошибок сети, затем разберёте границы сервисов, HTTP-контракты и конкурентные записи в PostgreSQL. Дальше идут gRPC с дедлайнами, повтор меняющего запроса, Kafka и связка outbox/inbox. Тесты отказов, логи, метрики и запуск через Docker Compose помогают увидеть, как система ведёт себя после сбоя. Go-задачи проверяют отдельные функции и сценарии, а работу нескольких процессов программа разбирает на локальных примерах. Так вы учитесь объяснять судьбу конкретной брони, а не просто перечислять компоненты архитектуры.
Начните с открытого урока о пустом ответе, 503, обрыве и повреждённом JSON. Представьте после каждого исхода, что известно клиенту, а что придётся выяснять у сервера. Затем откройте программу микросервисов на Go и пройдите путь от одного сетевого вызова до хранения, доставки событий и восстановления обработки.
