Войти Регистрация
Код-ревью

21. Пакетная обработка возвратов

Сложная

Java · 45 строк

Раз в 10 минут приходит пачка принятых возвратов: позиции из разных заказов, бывает по 3–4 позиции одного заказа. Сервис возвращает деньги через платёжный шлюз в пуле на 8 потоков и считает сумму возвратов по продавцу за день.

Если пачка упала, её обрабатывают повторно целиком. Отметьте строки с ошибками.

В работе: Возвраты денег покупателям: ошибка здесь — либо деньги не вернулись, либо вернулись дважды.

Как проверяем Нажмите на строку с ошибкой и коротко напишите, что не так. Баг засчитан, если отмечена хотя бы одна его строка. Зачёт — найдено не меньше 60 % багов с учётом серьёзности (критичный весит 3, обычный 2, мелкий 1), а лишних отметок не больше, чем багов в коде. Пустые строки, скобки и комментарии лишними не считаем. Ответ один на подход: после него показываем разбор.
пул потоковBigDecimalидемпотентностьгонки

Источник: на задачах Wildberries: возвраты товаров и денег. Условие пересказано своими словами.

Давали на собеседовании? Ответов пока мало — ваш поможет.
  1. @Service
  2. public class RefundService {
  3. private final OrderRepository orders;
  4. private final PaymentGateway gateway;
  5. private final ExecutorService pool = Executors.newFixedThreadPool(8);
  6. private final Map<Long, BigDecimal> refundedToday = new ConcurrentHashMap<>();
  7. public RefundService(OrderRepository orders, PaymentGateway gateway) {
  8. this.orders = orders;
  9. this.gateway = gateway;
  10. }
  11. public List<RefundResult> processReturns(List<ReturnItem> items) {
  12. List<Future<RefundResult>> futures = new ArrayList<>();
  13. for (ReturnItem item : items) {
  14. futures.add(pool.submit(() -> refund(item)));
  15. }
  16. List<RefundResult> results = new ArrayList<>();
  17. for (Future<RefundResult> f : futures) {
  18. try {
  19. results.add(f.get());
  20. } catch (Exception e) {
  21. results.add(RefundResult.failed());
  22. }
  23. }
  24. return results;
  25. }
  26. private RefundResult refund(ReturnItem item) {
  27. Order order = orders.findById(item.getOrderId());
  28. BigDecimal amount = order.getItemPrice(item.getSku())
  29. .multiply(BigDecimal.valueOf(item.getQuantity()));
  30. if (order.getRefunded().add(amount).compareTo(order.getTotal()) > 0) {
  31. return RefundResult.rejected("Сумма возврата больше суммы заказа");
  32. }
  33. if (amount.equals(BigDecimal.ZERO)) {
  34. return RefundResult.rejected("Нулевая сумма");
  35. }
  36. gateway.refund(order.getPaymentId(), amount);
  37. order.setRefunded(order.getRefunded().add(amount));
  38. orders.save(order);
  39. refundedToday.merge(order.getSellerId(), amount, BigDecimal::add);
  40. return RefundResult.ok(amount);
  41. }
  42. }