fix!: removed .commit() from repository level

This commit is contained in:
2026-08-24 11:07:26 +07:00
parent 8d1b753b99
commit a374501e4d
22 changed files with 177 additions and 180 deletions

View File

@@ -1,22 +1,17 @@
import asyncio
from datetime import UTC, datetime, timedelta
from typing import TYPE_CHECKING
from sqlalchemy import select
from sqlalchemy.dialects.postgresql import insert
from config import cfg
from db.models import ServiceNotification, Subscription
from db.session import async_session
from db.session import UnitOfWork, async_session
from schemas.enums import NotificationType
if TYPE_CHECKING:
from sqlalchemy.ext.asyncio import AsyncSession
async def collect_subscription_notifications(
session: "AsyncSession", now: datetime | None = None
) -> int:
async def collect_subscription_notifications(uow: UnitOfWork, now: datetime | None = None) -> int:
session = uow.session
now = now or datetime.now(UTC)
periods = (
(NotificationType.SEVEN_DAYS, now + timedelta(days=3), now + timedelta(days=7)),
@@ -48,7 +43,7 @@ async def collect_subscription_notifications(
result = await session.execute(stmt)
created += result.rowcount or 0
await session.commit()
await uow.commit()
return created
@@ -56,8 +51,8 @@ async def run_subscription_notifications() -> None:
interval = cfg.notification_scan_interval * 60
while True:
try:
async with async_session() as session:
await collect_subscription_notifications(session)
async with async_session() as session, UnitOfWork(session) as uow:
await collect_subscription_notifications(uow)
except Exception:
# A failed iteration must not stop subsequent notification checks.
pass

View File

@@ -6,7 +6,8 @@ from datetime import UTC, datetime
from config import cfg
from db.models.orders import OrderStatus
from db.models.transactions import BalanceTransaction, BalanceTxType
from db.models.transactions import BalanceTxType
from db.session import UnitOfWork
from repositories import AddonsRepository
from repositories.invoices import InvoiceRepository
from repositories.orders import OrderRepository
@@ -32,16 +33,17 @@ def validate_pally_signature(out_sum: str, inv_id: str, signature_value: str) ->
async def process_subscription_purchase( # noqa: PLR0911, PLR0912
session,
uow: UnitOfWork,
*,
invoice_id: int,
trs_id: str,
amount: int,
) -> None:
invoice_repo = InvoiceRepository(session)
orders_repo = OrderRepository(session)
users_repo = UserRepository(session)
pricing_repo = PricingRepository(session)
session = uow.session
invoice_repo = InvoiceRepository(uow)
orders_repo = OrderRepository(uow)
users_repo = UserRepository(uow)
pricing_repo = PricingRepository(uow)
invoice = await invoice_repo.get_by_id(invoice_id)
@@ -99,7 +101,7 @@ async def process_subscription_purchase( # noqa: PLR0911, PLR0912
subscription = user.subscription
now = datetime.now(UTC)
pricing = await get_pricing_model(AddonsRepository(session), pricing_repo)
pricing = await get_pricing_model(AddonsRepository(uow), pricing_repo)
logger.info(
"Processing payment: bill_id=%s, order_id=%s, user_id=%s, amount=%s",
@@ -142,19 +144,14 @@ async def process_subscription_purchase( # noqa: PLR0911, PLR0912
if referal_id is not None:
referal_amount = math.floor(amount * (cfg.referal_bonus / 100))
if referal_amount > 0:
referal_user = await session.get(type(user), referal_id)
referal_user = await users_repo.get_user_by_id(referal_id)
if referal_user is not None:
session.add(
BalanceTransaction(
user_id=referal_id,
amount=referal_amount,
tx_type=BalanceTxType.REFERRAL_BONUS,
balance_before=referal_user.balance,
balance_after=referal_user.balance + referal_amount,
description=f"referral reward for user {invoice.creator_id} (TrsId: {trs_id})",
)
await users_repo.increase_balance(
referal_id,
referal_amount,
BalanceTxType.REFERRAL_BONUS,
f"referral reward for user {invoice.creator_id} (TrsId: {trs_id})",
)
referal_user.balance += referal_amount
logger.info(
"Referral bonus processed: referrer_id=%s, amount=%s",
@@ -169,6 +166,6 @@ async def process_subscription_purchase( # noqa: PLR0911, PLR0912
trs_id,
)
await session.commit()
await uow.commit()
logger.info("Bill %s marked as PAID for TrsId %s", invoice_id, trs_id)

View File

@@ -8,7 +8,7 @@ from sqlalchemy.dialects.postgresql import insert
from config import cfg
from db.models import RWSyncOutbox, Subscription
from db.session import async_session
from db.session import UnitOfWork, async_session
from external.rw import sync_subscription_by_telegram_id
if TYPE_CHECKING:
@@ -48,7 +48,8 @@ async def enqueue_all_rw_syncs(session: "AsyncSession") -> int:
return count
async def process_rw_syncs(session: "AsyncSession", batch_size: int = 50) -> int:
async def process_rw_syncs(uow: UnitOfWork, batch_size: int = 50) -> int:
session = uow.session
now = datetime.now(UTC)
jobs = await session.scalars(
select(RWSyncOutbox)
@@ -63,7 +64,7 @@ async def process_rw_syncs(session: "AsyncSession", batch_size: int = 50) -> int
jobs = list(jobs)
for job in jobs:
job.locked_until = now + LOCK_DURATION
await session.commit()
await uow.commit()
for job in jobs:
subscription = job.subscription
@@ -81,7 +82,7 @@ async def process_rw_syncs(session: "AsyncSession", batch_size: int = 50) -> int
RWSyncOutbox.revision == job.revision,
)
)
await session.commit()
await uow.commit()
continue
delay = min(timedelta(minutes=2**job.attempts), MAX_RETRY_DELAY)
@@ -94,7 +95,7 @@ async def process_rw_syncs(session: "AsyncSession", batch_size: int = 50) -> int
locked_until=None,
)
)
await session.commit()
await uow.commit()
logger.warning("RW sync failed for subscription_id=%s", subscription.id)
return len(jobs)
@@ -104,8 +105,8 @@ async def run_rw_sync_worker() -> None:
interval = cfg.rw_sync_interval_minutes * 60
while True:
try:
async with async_session() as session:
await process_rw_syncs(session)
async with async_session() as session, UnitOfWork(session) as uow:
await process_rw_syncs(uow)
except Exception:
logger.exception("RW sync worker iteration failed")
await asyncio.sleep(interval)
@@ -116,8 +117,9 @@ async def run_rw_sync_reconciler() -> None:
while True:
try:
async with async_session() as session:
count = await enqueue_all_rw_syncs(session)
await session.commit()
async with UnitOfWork(session) as uow:
count = await enqueue_all_rw_syncs(uow.session)
await uow.commit()
logger.info("Queued %s subscriptions for RW reconciliation", count)
except Exception:
logger.exception("RW reconciliation iteration failed")