max / makenotwork
1 file changed,
+6 insertions,
-3 deletions
| @@ -493,9 +493,6 @@ pub(super) async fn blob_confirm_upload( | |||
| 493 | 493 | ))); | |
| 494 | 494 | } | |
| 495 | 495 | ||
| 496 | - | // Clear the pending upload record now that the upload is confirmed. | |
| 497 | - | db::pending_uploads::remove_pending_upload(&db, sync_user.user_id, &s3_key, "synckit").await?; | |
| 498 | - | ||
| 499 | 496 | // Record the blob and enforce the cap atomically. Internal apps gate on the | |
| 500 | 497 | // user's paid subscription + per-user cap; developer apps on the app/per-key | |
| 501 | 498 | // counters. Both are single-transaction (lock, check, insert, count). | |
| @@ -536,6 +533,12 @@ pub(super) async fn blob_confirm_upload( | |||
| 536 | 533 | ||
| 537 | 534 | match outcome { | |
| 538 | 535 | db::synckit::BlobConfirm::Stored | db::synckit::BlobConfirm::AlreadyStored => { | |
| 536 | + | // Only now that the blob is durably recorded do we drop the pending | |
| 537 | + | // row. Every refusal path below leaves it in place so the orphan reaper | |
| 538 | + | // (cleanup_orphaned_uploads) reclaims the unreferenced object; clearing | |
| 539 | + | // it before the quota gate stranded the object permanently and uncharged. | |
| 540 | + | db::pending_uploads::remove_pending_upload(&db, sync_user.user_id, &s3_key, "synckit") | |
| 541 | + | .await?; | |
| 539 | 542 | Ok(StatusCode::NO_CONTENT.into_response()) | |
| 540 | 543 | } | |
| 541 | 544 | db::synckit::BlobConfirm::NoSubscription => Ok(( |