Шлюз не ответил за 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 — что спрашивают на самом деле


В этом посте были ссылки, но мы их удалили по правилам Сетки