You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A production-style distributed URL shortener demonstrating caching, rate limiting, load balancing, and horizontal scalability. Built with a FastAPI backend, React frontend, PostgreSQL, Redis, Docker, and CI/CD (GitHub Actions).
3
+
A production-style distributed URL shortener demonstrating caching, rate limiting, load balancing, and horizontal scalability. Built with a FastAPI backend, React frontend, PostgreSQL, Redis, Docker, and CI (GitHub Actions).
4
4
5
5
## Live Demo
6
6
@@ -17,11 +17,14 @@ A lightweight React frontend provides a simple interface for:
17
17
18
18
The frontend communicates with the deployed FastAPI backend via REST APIs, enabling end-to-end interaction with the distributed system.
19
19
20
+
When the backend returns structured error details, such as rate-limit responses, the frontend surfaces those messages in the UI.
21
+
20
22
## Deployment
21
23
22
24
- Deployed on Render (cloud platform)
23
25
- Uses managed PostgreSQL as the persistent source of truth
24
26
- Redis is used as a shared cache and coordination layer in distributed environments, with graceful fallback when unavailable
27
+
- Reverse proxies should preserve `X-Forwarded-For` so Redis-backed rate limiting can identify individual clients correctly
25
28
- Environment-based configuration enables seamless switching between local, Docker, and cloud deployments
26
29
- Frontend deployed as a static site on Render, providing a user interface for interacting with backend APIs
27
30
@@ -55,6 +58,7 @@ Key goals:
55
58
- Stateless FastAPI services behind an Nginx load balancer
56
59
- PostgreSQL as the single source of truth for durability and consistency
57
60
- Redis used for shared caching and distributed rate limiting
61
+
- Rate limiting uses the first `X-Forwarded-For` address when requests pass through a reverse proxy or load balancer
58
62
- Horizontal scaling achieved via multiple stateless application replicas
59
63
- Graceful degradation when Redis is unavailable
60
64
@@ -66,7 +70,7 @@ Key goals:
66
70
- Cache redirect lookups using Redis
67
71
- Enforce request rate limits using Redis-backed distributed rate limiting
68
72
- Run the full stack locally using Docker Compose
69
-
- Validate system behavior with pytestand GitHub Actions CI
73
+
- Validate backend behavior with pytest, frontend behavior with Vitest, and backend CI checks with GitHub Actions
70
74
- Support horizontal scaling via stateless application instances behind a load balancer
71
75
- Benchmark cache performance (miss vs. hit latency)
72
76
@@ -76,14 +80,22 @@ To validate the effectiveness of Redis caching, redirect latency was measured fo
76
80
77
81
Run locally:
78
82
```bash
79
-
python scripts/benchmark_cache.py
83
+
python3 scripts/benchmark_cache.py
84
+
```
85
+
86
+
Optional environment overrides:
87
+
```bash
88
+
BENCHMARK_BASE_URL=http://127.0.0.1:8000 \
89
+
BENCHMARK_ORIGINAL_URL=https://www.google.com \
90
+
BENCHMARK_HIT_RUNS=20 \
91
+
python3 scripts/benchmark_cache.py
80
92
```
81
93
82
94
Example results:
83
95
84
-
- Cache miss latency: ~30–45 ms
85
-
- Average cache hit latency: ~6 ms
86
-
- Approximate speedup: ~5–7×
96
+
- Cache miss latency: ~10–32 ms
97
+
- Average cache hit latency: ~8–11 ms
98
+
- Approximate speedup: ~1–3×
87
99
88
100
This demonstrates that Redis caching significantly reduces redirect latency and minimizes repeated database queries in read-heavy workloads.
89
101
@@ -93,8 +105,8 @@ This demonstrates that Redis caching significantly reduces redirect latency and
93
105
- Implemented PostgreSQL-backed persistence as the durable source of truth for URL mappings and analytics
94
106
- Integrated Redis for shared caching and distributed rate limiting with graceful fallback when unavailable
95
107
- Containerized and orchestrated multiple application instances using Docker Compose to simulate a distributed environment
96
-
- Built automated test coverage with pytest to validate core workflows
97
-
- Configured GitHub Actions CI to run tests on every push and pull request
108
+
- Built automated test coverage with pytest for the backend and Vitest for the frontend
109
+
- Configured GitHub Actions CI to run backend tests on every push and pull request
98
110
- Introduced Nginx as a load balancer to distribute traffic across multiple FastAPI instances
99
111
- Validated Redis caching effectiveness using benchmark measurements (cache miss vs. hit latency)
100
112
@@ -105,10 +117,13 @@ This demonstrates that Redis caching significantly reduces redirect latency and
-`CORS_ALLOW_ORIGINS` — comma-separated frontend origins allowed to call the API
177
+
-`AUTO_CREATE_SCHEMA` — enables automatic table creation on startup; defaults to enabled in development/test and disabled in production-style environments
152
178
-`PORT` — application port
153
179
154
180
## Health Check
155
181
156
182
The service exposes a health check endpoint:
183
+
157
184
```http
158
185
GET /health
159
186
```
187
+
160
188
```bash
161
189
curl http://127.0.0.1:8000/health
162
190
```
163
191
164
192
## How to Run Locally
165
193
166
-
### Run Full Stack with Docker
194
+
### Run Backend Stack with Docker
167
195
168
196
```bash
169
197
docker compose up --build
170
198
```
199
+
171
200
Open:
172
201
- Backend API docs: http://127.0.0.1:8000/docs
173
202
- Backend health: http://127.0.0.1:8000/health
174
203
204
+
The Docker Compose backend stack runs `python -m alembic upgrade head` before starting the FastAPI replicas, so a fresh database is migrated automatically.
205
+
175
206
### Run Backend Locally (Services in Docker)
176
207
177
208
- Start required services:
178
209
```bash
179
210
docker compose up -d db redis
180
211
```
212
+
181
213
- Activate virtual environment:
182
214
```bash
183
215
source venv/bin/activate
184
216
```
217
+
185
218
- Install dependencies:
186
219
```bash
187
-
pip install -r requirements.txt
220
+
python3 -m pip install -r requirements.txt
188
221
```
222
+
223
+
- Configure local environment:
224
+
```bash
225
+
export BASE_URL=http://127.0.0.1:8000
226
+
```
227
+
228
+
For local runs, make sure `DATABASE_URL`, `REDIS_URL`, `BASE_URL`, and `AUTO_CREATE_SCHEMA` are set through your `.env` file or exported in the shell.
- For normal development and deployment, prefer migrations with:
301
+
```bash
302
+
AUTO_CREATE_SCHEMA=false
303
+
```
304
+
305
+
`AUTO_CREATE_SCHEMA=true` is still available for quick demo or prototyping workflows, but `AUTO_CREATE_SCHEMA=false` should be the default once the schema is managed by Alembic.
306
+
210
307
## Seed Sample Data
211
308
212
309
```bash
213
-
python -m scripts.seed
310
+
python3 -m alembic upgrade head
311
+
python3 -m scripts.seed
214
312
```
215
313
314
+
Run the migration step first when seeding a fresh database.
315
+
216
316
## Quick Demo Flow
217
317
218
-
- Start the full stack:
318
+
- Start the backend stack:
219
319
```bash
220
320
docker compose up --build
221
321
```
322
+
323
+
- In another terminal, start the frontend:
324
+
```bash
325
+
cd frontend
326
+
export VITE_API_BASE_URL=http://127.0.0.1:8000
327
+
npm run dev
328
+
```
329
+
222
330
- Open the frontend UI: http://localhost:5173
223
331
- Enter a URL (e.g., https://www.google.com) and generate a short link
224
332
- Open the returned short URL in your browser to verify redirection
@@ -333,4 +441,4 @@ Nginx Load Balancer
333
441
- Enhance rate limiting with sliding window or token bucket algorithms
334
442
- Implement custom aliases and expiration policies
335
443
- Build analytics aggregation pipeline for high-volume traffic
336
-
- Deploy multi-instance setup to the cloud using container orchestration (e.g., Kubernetes)
444
+
- Deploy multi-instance setup to the cloud using container orchestration (e.g., Kubernetes)
0 commit comments