TaskCrawler is an asynchronous web scraping processing system built with FastAPI, PostgreSQL, Redis and Docker.
The project demonstrates a scalable backend architecture where incoming scraping requests are decoupled from heavy network operations through a background worker and message queue.
Instead of keeping API requests waiting for scraping operations, the system creates jobs, stores their state, pushes tasks into Redis, and processes them asynchronously.
The system follows an event-driven architecture:
Client
|
|
v
FastAPI REST API
|
+--------+--------+
| |
v v
PostgreSQL Redis Queue
Job Storage Message Broker
|
|
v
Async Background Worker
|
|
v
HTTP Web Scraper
|
|
v
PostgreSQL Update
The API does not execute scraping operations during the HTTP request lifecycle.
When a URL is submitted:
- A scraping job is created.
- The job is stored in PostgreSQL.
- A message is published to Redis.
- A background worker processes the task.
- The final result is persisted.
This allows the API to remain responsive even during slow network operations.
Redis is used as a lightweight message broker.
The worker continuously listens for new scraping tasks using blocking queue operations.
Benefits:
- Decoupled processing
- Better scalability
- Independent worker execution
- Non-blocking API requests
The system prevents duplicated scraping tasks.
When a URL is submitted, the API checks if the same resource already exists.
If a previous job exists:
- The existing record is returned.
- A new scraping operation is not created.
This avoids unnecessary network requests and duplicate processing.
The scraping worker includes failure recovery mechanisms:
- Automatic retries
- Exponential backoff
- Random jitter delays
- Error persistence
Temporary network problems do not crash the worker.
Failed jobs are stored with error information for later inspection.
The application uses asynchronous I/O throughout the stack:
- FastAPI async endpoints
- SQLAlchemy AsyncIO
- asyncpg PostgreSQL driver
- redis.asyncio
- httpx.AsyncClient
This allows efficient handling of multiple operations without blocking threads.
- Python 3.11+
- FastAPI
- Pydantic
- SQLAlchemy AsyncIO
- Asyncpg
- HTTPX
- PostgreSQL 16
- Redis 7
- Docker
- Docker Compose
TaskCrawler/
│
├── main.py # FastAPI application and worker logic
├── database.py # Async database configuration
├── models.py # SQLAlchemy database models
├── config.py # Environment configuration
│
├── docker-compose.yml # Infrastructure setup
├── requirements.txt # Python dependencies
├── .env # Environment variables
│
└── README.md
Before running the project, install:
- Python 3.11+
- Docker
- Docker Compose
- PostegreSQL
git clone https://github.com/LUFFE154/TaskCrawler
cd TaskCrawlerStart PostgreSQL and Redis containers:
docker-compose up -dThe project requires:
PostgreSQL
localhost:5432
Redis
localhost:6379
Create a virtual environment:
python -m venv .venvActivate:
Windows:
.venv\Scripts\activateLinux/macOS:
source .venv/bin/activateInstall packages:
pip install -r requirements.txtCreate a .env file:
POSTGRES_ASYNC_URL=postgresql+asyncpg://app_db:app_db@127.0.0.1:5432/app_db
REDIS_URL=redis://127.0.0.1:6379/0Run:
uvicorn main:app --reloadThe API will be available at:
http://127.0.0.1:8000
Swagger documentation:
http://127.0.0.1:8000/docs
POST /api/v1/jobs
Example:
curl -X POST \
http://127.0.0.1:8000/api/v1/jobs \
-H "Content-Type: application/json" \
-d "{\"url\":\"https://example.com\"}"{
"id": "5c5ff4a0-9e0e-41bc-80fb-9c98f6f9c095",
"url": "https://example.com",
"status": "PENDING",
"retry_count": 0,
"scraped_title": null,
"error_log": null
}The API immediately returns the job identifier while processing continues asynchronously.
GET /api/v1/jobs/{job_id}
Example:
GET /api/v1/jobs/5c5ff4a0-9e0e-41bc-80fb-9c98f6f9c095
A job follows this lifecycle:
PENDING
|
v
PROCESSING
|
+------------+
| |
v v
COMPLETED FAILED
Successful processing:
{
"status": "COMPLETED",
"retry_count": 0,
"scraped_title": "Example Domain",
"error_log": null
}If a website cannot be reached:
{
"status": "FAILED",
"retry_count": 3,
"error_log": "Connection timeout"
}The worker retries automatically before marking the job as failed.
Redis provides a simple and fast queue mechanism between the API and workers.
Advantages:
- Low latency
- Easy horizontal scaling
- Reliable message passing
Web scraping is highly I/O-bound.
Using asynchronous programming allows the application to:
- Handle multiple network operations efficiently
- Avoid blocking execution
- Improve throughput
PostgreSQL stores:
- Job metadata
- Processing state
- Results
- Errors
It provides reliable persistence and transactional guarantees.
Planned improvements:
- Multiple worker processes
- Distributed worker scaling
- Better HTML extraction
- OpenGraph metadata extraction
- Link relationship mapping
- Authentication and authorization
- Rate limiting
- Monitoring with Prometheus/Grafana
- Docker production deployment
- Vector database integration for RAG pipelines
This project is licensed under the MIT License.
Luiz Fernando Pio Ferreira
Backend Developer
Technologies:
Python • FastAPI • PostgreSQL • Redis • Docker • Async Systems