python
55 lines · 8 steps
A background session cleaner in FastAPI
Run a periodic expired-session purge as a background task tied to the FastAPI app lifespan.
Explained by
highlit
1import asyncio
2import logging
3from contextlib import asynccontextmanager
4from datetime import datetime, timedelta, timezone
5
6from fastapi import FastAPI
7
8from .database import async_session
9from .models import Session as UserSession
10from sqlalchemy import delete
11
12logger = logging.getLogger(__name__)
13
14CLEANUP_INTERVAL = 300
15SESSION_TTL = timedelta(hours=24)
16
17
18async def purge_expired_sessions() -> int:
19 cutoff = datetime.now(timezone.utc) - SESSION_TTL
20 async with async_session() as db:
21 result = await db.execute(
22 delete(UserSession).where(UserSession.last_seen_at < cutoff)
23 )
24 await db.commit()
25 return result.rowcount
26
27
28async def cleanup_loop() -> None:
29 while True:
30 try:
31 await asyncio.sleep(CLEANUP_INTERVAL)
32 removed = await purge_expired_sessions()
33 if removed:
34 logger.info("Purged %d expired sessions", removed)
35 except asyncio.CancelledError:
36 logger.info("Cleanup loop stopping")
37 raise
38 except Exception:
39 logger.exception("Session cleanup failed; retrying next tick")
40
41
42@asynccontextmanager
43async def lifespan(app: FastAPI):
44 task = asyncio.create_task(cleanup_loop())
45 try:
46 yield
47 finally:
48 task.cancel()
49 try:
50 await task
51 except asyncio.CancelledError:
52 pass
53
54
55app = FastAPI(lifespan=lifespan)
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1A lifespan context manager is the clean place to start and stop background work alongside the app.
- 2Cancelling a task and awaiting it lets the coroutine unwind its cleanup before shutdown completes.
- 3Catching broad exceptions inside the loop keeps one bad tick from killing the whole worker.
Related explainers
python
from fastapi import FastAPI, WebSocket, WebSocketDisconnect app = FastAPI()
Building a WebSocket chat with FastAPI
websockets
broadcast
connection-management
Intermediate
9 steps
python
import time import uuid from django.utils.deprecation import MiddlewareMixin
Attaching per-request context in Django
middleware
request lifecycle
multi-tenancy
Intermediate
7 steps
python
import random from typing import Iterator, List
How reservoir sampling picks k items
reservoir-sampling
streaming
randomness
Intermediate
5 steps
python
import secrets from django.contrib.auth import authenticate, login from django.core.cache import cache
Two-factor login with OTP in Django
two-factor-auth
one-time-passwords
caching
Intermediate
9 steps
python
import re from functools import total_ordering from typing import Optional
Parsing and comparing semantic versions
regex
operator-overloading
sorting
Intermediate
7 steps
python
from typing import Any, Sequence, Mapping def render_markdown_table(
Rendering an aligned Markdown table in Python
string formatting
data transformation
closures
Intermediate
8 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/a-background-session-cleaner-in-fastapi-explained-python-3bb6/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.