search for standard sites pub-search.waow.tech
search zig blog atproto
at main 107 lines 3.2 kB view raw
1#!/usr/bin/env -S uv run --script --quiet 2# /// script 3# requires-python = ">=3.12" 4# dependencies = ["httpx"] 5# /// 6""" 7Exercise all leaflet-search API endpoints to generate traffic. 8 9Usage: 10 ./scripts/exercise-api # run with defaults 11 ./scripts/exercise-api --count 20 # more requests per endpoint 12 13Check logfire for latency/error data after running. 14""" 15 16import asyncio 17import random 18import sys 19 20import httpx 21 22BASE_URL = "https://leaflet-search-backend.fly.dev" 23 24SEARCH_QUERIES = [ 25 "python", "rust", "zig", "javascript", "typescript", 26 "prefect", "workflow", "automation", "data", "api", 27 "database", "sqlite", "machine learning", "llm", "claude", 28 "bluesky", "atproto", "leaflet", "publishing", "markdown", 29 "web", "server", "deploy", "docker", "async", 30] 31 32 33async def exercise_search(client: httpx.AsyncClient, count: int): 34 """Hit search endpoint with various queries.""" 35 print(f"search: {count} requests...") 36 for i in range(count): 37 q = random.choice(SEARCH_QUERIES) 38 resp = await client.get(f"/search", params={"q": q}) 39 if resp.status_code != 200: 40 print(f" search failed: {resp.status_code}") 41 print(f" done") 42 43 44async def exercise_similar(client: httpx.AsyncClient, count: int): 45 """Hit similar endpoint with document URIs.""" 46 print(f"similar: {count} requests...") 47 # first get some URIs from search 48 resp = await client.get("/search", params={"q": "python"}) 49 if resp.status_code != 200: 50 print(" failed to get URIs") 51 return 52 docs = resp.json() 53 if not docs: 54 print(" no docs found") 55 return 56 57 uris = [d["uri"] for d in docs[:5]] 58 for i in range(count): 59 uri = random.choice(uris) 60 resp = await client.get("/similar", params={"uri": uri}) 61 if resp.status_code != 200: 62 print(f" similar failed: {resp.status_code}") 63 print(f" done") 64 65 66async def exercise_tags(client: httpx.AsyncClient, count: int): 67 """Hit tags endpoint.""" 68 print(f"tags: {count} requests...") 69 for i in range(count): 70 resp = await client.get("/tags") 71 if resp.status_code != 200: 72 print(f" tags failed: {resp.status_code}") 73 print(f" done") 74 75 76async def exercise_popular(client: httpx.AsyncClient, count: int): 77 """Hit popular endpoint.""" 78 print(f"popular: {count} requests...") 79 for i in range(count): 80 resp = await client.get("/popular") 81 if resp.status_code != 200: 82 print(f" popular failed: {resp.status_code}") 83 print(f" done") 84 85 86async def main(): 87 count = 12 88 if "--count" in sys.argv: 89 idx = sys.argv.index("--count") 90 if idx + 1 < len(sys.argv): 91 count = int(sys.argv[idx + 1]) 92 93 print(f"exercising {BASE_URL} ({count} requests per endpoint)\n") 94 95 async with httpx.AsyncClient(base_url=BASE_URL, timeout=30) as client: 96 await asyncio.gather( 97 exercise_search(client, count), 98 exercise_similar(client, count), 99 exercise_tags(client, count), 100 exercise_popular(client, count), 101 ) 102 103 print("\ndone - check logfire for results") 104 105 106if __name__ == "__main__": 107 asyncio.run(main())