Шлюз не ответил за 5 секунд. Что делает ваш код?
Этот вопрос проверяют не ради теории про таймауты. Проверяют, понимает ли кандидат, что отсутствие ответа — это не "операция не выполнена", а "статус неизвестен". Списание могло пройти на стороне банка, а ответ просто не долетел.
Если на таймаут вы просто ретраите запрос списания — вы рискуете списать деньги дважды. Если игнорируете и помечаете заказ как "ошибка оплаты" — рискуете потерять деньги клиента, который на самом деле заплатил.
Правильный путь — идемпотентный ключ, который генерируется на вашей стороне ДО первого запроса и передаётся при каждом повторе. Платёжный шлюз должен поддерживать его на своей стороне: увидев повторный ключ, он возвращает результат первой попытки, а не выполняет списание заново.
String idempotencyKey = UUID.randomUUID().toString(); // ключ сохраняется в заказе ДО вызова order.setIdempotencyKey(idempotencyKey); orderRepository.save(order);
PaymentRequest request = PaymentRequest.builder() .amount(order.getAmount()) .idempotencyKey(idempotencyKey) .build();
// при ретрае передаём тот же ключ, а не новый paymentClient.charge(request);
Следом спросят: а что если клиент сам инициирует повторную оплату и генерирует новый ключ? Тогда вся защита бесполезна — ключ должен жить на стороне сервера, привязанный к заказу, а не передаваться клиентом как есть. И второй вопрос: как долго хранить ключ и что возвращать, если шлюз сам ещё не ответил на первую попытку — тут нужен статус "в процессе", а не просто "успех/ошибка".
Таймаут от внешнего сервиса — это всегда неопределённость, а не отрицательный ответ. Код, который путает эти два состояния, рано или поздно задублирует платёж.
senior·base — что спрашивают на самом деле
В этом посте были ссылки, но мы их удалили по правилам Сетки