From a296d287100b26f12e1bb9da267d33332d41967b Mon Sep 17 00:00:00 2001 From: Jordan Cook Date: Thu, 27 Oct 2022 12:52:08 -0500 Subject: Add example with requests per second graph --- .gitignore | 14 +++--- docs/examples.md | 27 +++++++++++ examples/rps_graph.png | Bin 0 -> 36120 bytes examples/rps_graph.py | 123 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 158 insertions(+), 6 deletions(-) create mode 100644 examples/rps_graph.png create mode 100644 examples/rps_graph.py diff --git a/.gitignore b/.gitignore index b501189..1ee54e2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,17 +1,19 @@ -*.db -*.py[cod] -*.sqlite -*.sqlite-journal -*.egg -*.egg-info build/ dist/ downloads/ example_cache/ http_cache/ venv/ + +*.db +*.egg +*.egg-info +*.py[cod] +*.sqlite +*.sqlite-journal .venv Pipfile +profile.json # JS node_modules/ diff --git a/docs/examples.md b/docs/examples.md index 3beba85..d193680 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -175,6 +175,33 @@ The following scripts can also be found in the ``` ::: + +### Requests per second graph +```{include} ../examples/rps_graph.py +:start-line: 2 +:end-line: 7 +``` + +:::{dropdown} Example +:animate: fade-in-slide-down +:color: primary +:icon: file-code + +[benchmark.py](https://github.com/requests-cache/requests-cache/blob/main/examples/rps_graph.py) +```{literalinclude} ../examples/rps_graph.py +:lines: 9- +``` +::: + +:::{dropdown} Screenshot +:animate: fade-in-slide-down +:color: info +:icon: image + +![](../examples/rps_graph.png) + +::: + ### Using with GitHub Actions This example shows how to use requests-cache with [GitHub Actions](https://docs.github.com/en/actions). Key points: diff --git a/examples/rps_graph.png b/examples/rps_graph.png new file mode 100644 index 0000000..ff8b633 Binary files /dev/null and b/examples/rps_graph.png differ diff --git a/examples/rps_graph.py b/examples/rps_graph.py new file mode 100644 index 0000000..172ef78 --- /dev/null +++ b/examples/rps_graph.py @@ -0,0 +1,123 @@ +#!/usr/bin/env python +""" +This example displays a graph of request rates over time. Requests are continuously sent to URLs +randomly picked from a fixed number of possible URLs. This demonstrates how average request rate +increases as the proportion of cached requests increases. + +Try running this example with different cache settings and URLs to see how the graph changes. +""" +from random import randint +from time import time + +from rich.live import Live +from rich.progress import BarColumn, MofNCompleteColumn, Progress +from rich.table import Table + +from requests_cache import CachedSession + +N_UNIQUE_REQUESTS = 200 + + +class RPSProgress(Progress): + """Display a bar chart of requests per second""" + + def __init__(self, interval: int = 1, scale: int = 500, **kwargs): + super().__init__(BarColumn(), '{task.completed}', **kwargs) + self.current_task = None + self.interval = interval + self.interval_start = None + self.scale = scale + self.total_requests = 0 + self.next_interval() + + def next_interval(self): + """Create a new task to draw the next line on the bar chart""" + self.current_task = self.add_task('barchart_line', total=self.scale) + self.interval_start = time() + + def count_request(self): + if time() - self.interval_start >= self.interval: + self.next_interval() + self.advance(self.current_task) + self.total_requests += 1 + + +class CacheRPSProgress: + """Track requests per second plus cache size in a single live view""" + + def __init__(self, n_unique_requests: int = 100): + self.rps_progress = RPSProgress() + self.cache_progress = Progress( + BarColumn(complete_style='blue'), + '[cyan]Requests cached:', + MofNCompleteColumn(), + ) + header = Progress(BarColumn(), '[cyan]Requests per second') + header.add_task('') + self.cache_task = self.cache_progress.add_task('', total=n_unique_requests) + self.n_unique_requests = n_unique_requests + self.start_time = time() + + self.table = Table.grid() + self.table.add_row(header) + self.table.add_row(self.rps_progress) + self.table.add_row(self.cache_progress) + self.live = Live(self.table, refresh_per_second=10) + + def __enter__(self): + """Start live view on ctx enter""" + self.live.__enter__() + self.log( + '[cyan]Measuring request rate with ' + f'[white]{self.n_unique_requests}[cyan] total unique requests' + ) + self.log('[cyan]Press [white]Ctrl+C[cyan] to exit') + return self + + def __exit__(self, *args): + """Show stats on ctx exit""" + self.live.__exit__(*args) + elapsed = time() - self.start_time + self.log( + f'[cyan]Sent a total of [white]{self.total_requests}[cyan] ' + f'requests in [white]{elapsed:.2f}[cyan] seconds ' + ) + + self.log(f'[cyan]Average: [white]{int(self.total_requests/elapsed)}[cyan] requests/second') + + @property + def total_requests(self): + return self.rps_progress.total_requests + + def count_request(self): + self.rps_progress.count_request() + + def update_cache_size(self, size: int): + self.cache_progress.update(self.cache_task, completed=size) + + def log(self, msg: str): + self.cache_progress.log(msg) + + +def test_rps(session): + session.cache.clear() + + # Send a request to one of a fixed number of unique URLs + def random_request(): + request_number = randint(1, N_UNIQUE_REQUESTS) + session.get(f'https://httpbin.org/get?page={request_number}') + + # Show request rate over time and total cached (unexpired) requests + with CacheRPSProgress(N_UNIQUE_REQUESTS) as progress: + while True: + try: + random_request() + progress.count_request() + progress.update_cache_size(session.cache.responses.count(expired=False)) + except KeyboardInterrupt: + break + + +if __name__ == '__main__': + session = CachedSession(use_temp=True, expire_after=30) + test_rps(session) -- cgit v1.2.1