diff --git a/apps/labrinth/.sqlx/query-8f51f552d1c63fa818cbdba581691e97f693a187ed05224a44adeee68c6809d1.json b/apps/labrinth/.sqlx/query-6cd0cfece6d87d039bb22379045509824d2c9eee5e1864a15186e713394f5926.json similarity index 94% rename from apps/labrinth/.sqlx/query-8f51f552d1c63fa818cbdba581691e97f693a187ed05224a44adeee68c6809d1.json rename to apps/labrinth/.sqlx/query-6cd0cfece6d87d039bb22379045509824d2c9eee5e1864a15186e713394f5926.json index d28e9a721..963a92a47 100644 --- a/apps/labrinth/.sqlx/query-8f51f552d1c63fa818cbdba581691e97f693a187ed05224a44adeee68c6809d1.json +++ b/apps/labrinth/.sqlx/query-6cd0cfece6d87d039bb22379045509824d2c9eee5e1864a15186e713394f5926.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n id, user_id, price_id, amount, currency_code, status, due, last_attempt,\n charge_type, subscription_id,\n -- Workaround for https://github.com/launchbadge/sqlx/issues/3336\n subscription_interval AS \"subscription_interval?\",\n payment_platform,\n payment_platform_id AS \"payment_platform_id?\",\n parent_charge_id AS \"parent_charge_id?\",\n net AS \"net?\"\n FROM charges\n \n WHERE\n charge_type = $1 AND\n (\n (status = 'open' AND due < NOW()) OR\n (status = 'failed' AND last_attempt < NOW() - INTERVAL '2 days')\n )\n ", + "query": "\n SELECT\n id, user_id, price_id, amount, currency_code, status, due, last_attempt,\n charge_type, subscription_id,\n -- Workaround for https://github.com/launchbadge/sqlx/issues/3336\n subscription_interval AS \"subscription_interval?\",\n payment_platform,\n payment_platform_id AS \"payment_platform_id?\",\n parent_charge_id AS \"parent_charge_id?\",\n net AS \"net?\"\n FROM charges\n \n WHERE\n charge_type = $1 AND\n (\n (status = 'open' AND due < NOW()) OR\n (status = 'failed' AND last_attempt < NOW() - INTERVAL '2 days')\n )\n FOR UPDATE SKIP LOCKED\n ", "describe": { "columns": [ { @@ -102,5 +102,5 @@ true ] }, - "hash": "8f51f552d1c63fa818cbdba581691e97f693a187ed05224a44adeee68c6809d1" + "hash": "6cd0cfece6d87d039bb22379045509824d2c9eee5e1864a15186e713394f5926" } diff --git a/apps/labrinth/src/database/models/charge_item.rs b/apps/labrinth/src/database/models/charge_item.rs index 8a9884075..115af564f 100644 --- a/apps/labrinth/src/database/models/charge_item.rs +++ b/apps/labrinth/src/database/models/charge_item.rs @@ -206,8 +206,8 @@ impl ChargeItem { Ok(res.and_then(|r| r.try_into().ok())) } - pub async fn get_chargeable( - exec: impl sqlx::Executor<'_, Database = sqlx::Postgres>, + pub async fn get_chargeable_lock( + transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>, ) -> Result, DatabaseError> { let charge_type = ChargeType::Subscription.as_str(); let res = select_charges_with_predicate!( @@ -218,10 +218,11 @@ impl ChargeItem { (status = 'open' AND due < NOW()) OR (status = 'failed' AND last_attempt < NOW() - INTERVAL '2 days') ) + FOR UPDATE SKIP LOCKED "#, charge_type ) - .fetch_all(exec) + .fetch_all(&mut **transaction) .await?; Ok(res diff --git a/apps/labrinth/src/routes/internal/billing.rs b/apps/labrinth/src/routes/internal/billing.rs index 469555946..4af586ed6 100644 --- a/apps/labrinth/src/routes/internal/billing.rs +++ b/apps/labrinth/src/routes/internal/billing.rs @@ -2271,9 +2271,11 @@ pub async fn index_billing( info!("Indexing billing queue"); let res = async { // If a charge is open and due or has been attempted more than two days ago, it should be processed + let mut transaction = pool.begin().await?; + let charges_to_do = - crate::database::models::charge_item::ChargeItem::get_chargeable( - &pool, + crate::database::models::charge_item::ChargeItem::get_chargeable_lock( + &mut transaction, ) .await?; @@ -2396,8 +2398,11 @@ pub async fn index_billing( charge.status = ChargeStatus::Processing; - stripe::PaymentIntent::create(&stripe_client, intent) - .await?; + if let Err(e) = stripe::PaymentIntent::create(&stripe_client, intent).await { + tracing::error!("Failed to create payment intent: {:?}", e); + charge.status = ChargeStatus::Failed; + charge.last_attempt = Some(Utc::now()); + } } else { charge.status = ChargeStatus::Failed; charge.last_attempt = Some(Utc::now());