Skip to content

Commit 9f0d731

Browse files
committed
Autoclose orphaned sessions
1 parent 2870738 commit 9f0d731

2 files changed

Lines changed: 25 additions & 0 deletions

File tree

app/api/v1/sessions.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,27 @@
2020

2121
router = APIRouter()
2222

23+
_STALE_GRACE = timedelta(minutes=5)
24+
25+
26+
def close_stale_sessions(db: Session) -> int:
27+
"""Close sessions whose paid_until has been exceeded by more than 5 minutes.
28+
29+
Sets end_time = paid_until for each such session. Returns the number closed.
30+
Called from the health endpoint (periodic) and session creation (on demand).
31+
"""
32+
cutoff = datetime.now(UTC).replace(tzinfo=None) - _STALE_GRACE
33+
stale = (
34+
db.query(MachineSession)
35+
.filter(MachineSession.end_time.is_(None), MachineSession.paid_until < cutoff)
36+
.all()
37+
)
38+
for s in stale:
39+
s.end_time = s.paid_until
40+
if stale:
41+
db.commit()
42+
return len(stale)
43+
2344

2445
def _calc_max_seconds(
2546
balance: Decimal, price_per_minute: Decimal, remaining_seconds: float
@@ -43,6 +64,8 @@ def create_session(
4364
Deducts: price_per_login + price_per_minute * booking_interval
4465
Requires: balance >= that amount
4566
"""
67+
close_stale_sessions(db)
68+
4669
# Lock user row for atomic balance check
4770
user = db.execute(
4871
select(User).where(User.id == body.nfc_id).with_for_update()

app/main.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class JSONResponse(_JSONResponse):
1515
from starlette.middleware.sessions import SessionMiddleware
1616

1717
from app.api.v1.router import api_router
18+
from app.api.v1.sessions import close_stale_sessions
1819
from app.config import settings
1920
from app.database import get_db
2021
from app.web.router import router as web_router
@@ -85,6 +86,7 @@ def health(db: Session = Depends(get_db)):
8586
"""Public health check. Returns 200 when the database is reachable."""
8687
try:
8788
db.execute(text("SELECT 1"))
89+
close_stale_sessions(db)
8890
return {"status": "ok", "database": "ok"}
8991
except Exception:
9092
return JSONResponse({"status": "error", "database": "unreachable"}, status_code=503)

0 commit comments

Comments
 (0)