Какие способы взаимодействия между сервисами используются: REST или другие интеграции?
Что проверяют
Знаете ли вы, чем синхронный вызов отличается от асинхронного по последствиям, и умеете ли реализовать это на Go без сюрпризов. Следом обычно спрашивают, как вы передаёте таймауты по цепочке сервисов и что будет, если получатель события упал.
Как отвечать
Разделите способы на синхронные и асинхронные и для каждого назовите инструменты:
- REST поверх HTTP: стандартный
net/http, с Go 1.22 маршрутизатор понимает метод и параметры пути вродеGET /users/{id}, поэтому сторонний роутер нужен не всегда. Контракт описывают в OpenAPI, код генерируют, например, черезoapi-codegen; - gRPC:
grpc-go, контракт в.proto, генерация черезprotoc-gen-goилиbuf. Строгая типизация, HTTP/2, стриминг, дедлайны встроены в протокол. Основной выбор для внутренних вызовов в Go-сервисах; - GraphQL: скорее для фронтенда, в Go обычно через
gqlgen; - брокеры: Kafka через
franz-goилиsegmentio/kafka-go, RabbitMQ, NATS, который сам написан на Go и популярен в этой среде. Отправитель не ждёт получателя, пики нагрузки сглаживаются.
Выбор: синхронно, когда ответ нужен для продолжения запроса; асинхронно, когда нужна гарантия обработки, а не мгновенный результат.
Отдельно покажите работу с context.Context. Входящий запрос приносит дедлайн, вы передаёте контекст в каждый исходящий вызов, а gRPC отправляет дедлайн в заголовке, и следующий сервис получает его в своём контексте. Плюс повторы с экспоненциальной задержкой только для идемпотентных операций, circuit breaker, идемпотентные обработчики сообщений, потому что брокеры обычно доставляют «хотя бы один раз», и Transactional Outbox, чтобы запись в базу и публикация события не разъехались.
Где спотыкаются
Используют http.DefaultClient или &http.Client{} без Timeout. По умолчанию таймаута нет, и зависший сервис держит горутины и соединения бесконечно.
Не закрывают resp.Body и не вычитывают его до конца. Соединения не возвращаются в пул, и под нагрузкой сервис упирается в лимит сокетов.
Создают новый context.Background() внутри обработчика вместо того, чтобы передать контекст запроса. Отмена со стороны клиента и дедлайн теряются, а работа продолжается впустую.