Initial import

This commit is contained in:
2026-03-05 14:27:30 +00:00
commit bcbf9155d7
26 changed files with 841 additions and 0 deletions

45
backend/main.py Normal file
View File

@@ -0,0 +1,45 @@
from fastapi import FastAPI, Depends, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from database.session import get_db
from database.models import Ticket, TicketStatus
from core.redis import acquire_seat_lock, release_seat_lock
from api.routers.auth import router as auth_router
app = FastAPI(title="Ticketing System API")
app.include_router(auth_router)
@app.post("/api/seats/{seat_id}/lock", status_code=status.HTTP_200_OK)
async def lock_seat(seat_id: int, user_id: int, db: AsyncSession = Depends(get_db)):
# 1. Проверяем статус в БД (грязное чтение, чтобы отсеять уже выкупленные билеты)
query = select(Ticket).where(Ticket.seat_id == seat_id)
result = await db.execute(query)
ticket = result.scalar_one_or_none()
if ticket and ticket.status != TicketStatus.AVAILABLE:
raise HTTPException(status_code=409, detail="Seat is already booked or locked in DB")
# 2. Пытаемся захватить распределенную блокировку в Redis (15 минут по ТЗ)
locked = await acquire_seat_lock(seat_id=seat_id, user_id=user_id)
if not locked:
raise HTTPException(status_code=409, detail="Seat is currently locked by another user")
# 3. Лок наш. Пишем статус в PostgreSQL
try:
if not ticket:
ticket = Ticket(seat_id=seat_id, user_id=user_id, status=TicketStatus.LOCKED)
db.add(ticket)
else:
ticket.status = TicketStatus.LOCKED
ticket.user_id = user_id
await db.commit()
return {"message": "Seat locked successfully", "seat_id": seat_id, "status": "LOCKED"}
except Exception as e:
# Критически важно: если БД отвалилась, снимаем лок в Redis, иначе место зависнет на 15 минут
await release_seat_lock(seat_id)
await db.rollback()
raise HTTPException(status_code=500, detail="Database transaction failed")