Skip to content

Commit 77c3059

Browse files
committed
fix(promo-codes): prevent partial-reservation leak on mid-loop failure
Codex audit of ad113d5 caught a real BUG. Saga::run() at SummitOrderService.php:131-134 only calls markAsRan() AFTER a task's run() returns. If reserveMemberQuotas() succeeds for code A and then throws on code B, the exception propagates before PreProcessReservationTask is in $already_run_tasks, so saga abort() never invokes this task's undo() — leaking code A's counter increment on the durable reservation row. Guard reserveMemberQuotas() with a local try/catch in run() that calls $this->undo() (idempotent via the $undone flag) before rethrowing, so any partial progress is released whether or not the saga reaches us. Found by Codex review, patch as proposed.
1 parent ad113d5 commit 77c3059

1 file changed

Lines changed: 11 additions & 1 deletion

File tree

app/Services/Model/Imp/SummitOrderService.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1151,7 +1151,17 @@ public function run(array $formerState): array
11511151
}
11521152
}
11531153

1154-
$this->reserveMemberQuotas($promo_codes_usage);
1154+
// Saga::run() only marks a task as "ran" AFTER run() returns. If
1155+
// reserveMemberQuotas() succeeds for code A then throws on code B,
1156+
// the exception propagates before markAsRan(), so saga abort()
1157+
// never calls this task's undo() — leaking code A's reservation.
1158+
// Guard by running our own undo locally before rethrowing.
1159+
try {
1160+
$this->reserveMemberQuotas($promo_codes_usage);
1161+
} catch (\Exception $ex) {
1162+
$this->undo();
1163+
throw $ex;
1164+
}
11551165

11561166
return [
11571167
"reservations" => $reservations,

0 commit comments

Comments
 (0)