A CLI tool that starts a caching proxy server. The proxy serves responses from cache when possible; on a miss it forwards the request to the origin server and stores the response. Based on the caching proxy challenge from Roadmap.sh
Before running the project, make sure you have:
- Docker and Docker Compose installed
- Python if you want to run cli without docker
git clone git@github.com:Nyk00s/cache-proxy.git
cd cache-proxyIf you want to change default configuration add this line to docker-compose file, and set flags as you want:
command: caching-proxy --port 3000 --origin https://dummyjson.comdocker compose up -d --buildcurl -i http://localhost:3000/products/1 # X-Cache: MISS
curl -i http://localhost:3000/products/1 # X-Cache: HITIf you want to start the CLI without docker:
docker compose up -d cache_serverThe CLI still needs docker to run the cache service.
a) Create virtual environment
python -m venv .venvb) activate virtual environment
Windows:
.\.venv\Scripts\activate Linux:
source .venv/bin/activatec) Install requirements
pip install .if you want to run tests as well:
pip install -e ".[dev]"d) Run CLI
If you need help with flags type this:
caching-proxy --helpexample start command:
caching-proxy --port 3000 --origin https://dummyjson.comAvailable flags:
- --port - set the port of caching proxy service. default value: 3000
- --origin set the origin default value: https://dummyjson.com
- --clear-cache clear all cache
If you want to clear cache when docker hosts services:
docker compose run proxy caching-proxy --clear-cache-
I decided to design key like that: "method:path:query", query is being sorted (a=1&b=2 is equal to b=2&a=1).
-
Internal errors are not stored in cache, as well as redirects (consumed by requests module) so only 2xx and 4xx are processed.
-
For 2xx ttl is set to 300 seconds, 4xx are set for 60, it is shorter because for example data can be created, we cache it to protect origin against cache penetration.
-
Headers are filtered and hop-by-hop are deleted.
-
Cache has default policy (allkeys-lru) without persistence.
-
Project is divided into models, service, utils, cache, origin, cli, app, bootstrap. These create composition root.
-
Dependencies are injected via constructors, communication with cache and origin is isolated in different classes.
-
Tests are without any library mocks, I wrote own fake objects.
Some of the headers aren't processed like Vary / Accept, status codes like 429 as well.
Python requests module consumes redirects.
Only GET method is processed.
No cache stampede protection - when a popular key expires, concurrent requests may all hit the origin at once.
If you installed requirements with -e flag you can run tests like this:
python -m pytest -vTests cover in 100% ProxyService, models, utils, app tested by TestClient from fastapi. Origin and Cache (classes that provide communication with cache and origin) aren't fully tested because they need access to redis or network. Cli isn't tested because it only parses arguments