Код выглядит аккуратно. Но данные теряются, и никто не знает почему 👇
📦 Задание
Есть сервис для обработки платежей. Код покрыт тестами, транзакции есть, ошибки логируются. На проде раз в несколько дней часть платежей пропадает — в БД нет записи, в логах нет ошибок, пользователь уверен что оплатил.
// src/Payment/PaymentService.php
class PaymentService
{
public function __construct(
private PDO $pdo,
private Logger $logger,
private Notifier $notifier,
) {}
public function process(PaymentDTO $dto): bool
{
try {
$this->pdo->beginTransaction();
$paymentId = $this->insertPayment($dto);
$this->updateBalance($dto->userId, $dto->amount);
$this->insertAuditLog($paymentId, $dto);
$this->pdo->commit();
$this->notifier->sendReceipt($dto->userId, $paymentId);
return true;
} catch (NotificationException $e) {
$this->logger->warning('Receipt failed', ['error' => $e->getMessage()]);
return true;
} catch (Throwable $e) {
$this->logger->error('Payment failed', ['error' => $e->getMessage()]);
$this->pdo->rollBack();
return false;
}
}
private function insertPayment(PaymentDTO $dto): int
{
$stmt = $this->pdo->prepare(
'INSERT INTO payments (user_id, amount, status) VALUES (?, ?, ?)'
);
$stmt->execute([$dto->userId, $dto->amount, 'pending']);
return (int) $this->pdo->lastInsertId();
}
private function updateBalance(int $userId, float $amount): void
{
$stmt = $this->pdo->prepare(
'UPDATE balances SET amount = amount - ? WHERE user_id = ?'
);
$stmt->execute([$amount, $userId]);
if ($stmt->rowCount() === 0) {
throw new \RuntimeException("Balance record not found for user $userId");
}
}
private function insertAuditLog(int $paymentId, PaymentDTO $dto): void
{
// Пишем в отдельную audit БД через отдельное соединение
$this->auditPdo->prepare(
'INSERT INTO audit_log (payment_id, user_id, amount) VALUES (?, ?, ?)'
);
// ... execute
}
}
🔹 Задачи
— Найти сценарий, при котором платёж коммитится в БД, но return true не доходит до контроллера — и данные считаются потерянными
— Объяснить проблему
— Предложить исправленную структуру
Ставьте → 🔥 если нравится формат. Если нет → 🌚
💬 Решения пишите в комменты под спойлер — сравним подходы.