from socketify import App import redis import aiohttp import asyncio from helpers.twolevel_cache import TwoLevelCache #create redis poll + connections redis_pool = redis.ConnectionPool(host='localhost', port=6379, db=0) redis_conection = redis.Redis(connection_pool=redis_pool) # 2 LEVEL CACHE (Redis to share amoung workers, Memory to be much faster) # cache in memory is 30s, cache in redis is 60s duration cache = TwoLevelCache(redis_conection, 30, 60) ### # Model ### async def get_pokemon(number): async with aiohttp.ClientSession() as session: async with session.get(f'https://pokeapi.co/api/v2/pokemon/{number}') as response: pokemon = await response.text() #cache only works with strings/bytes #we will not change nothing here so no needs to parse json return pokemon.encode("utf-8") async def get_original_pokemons(): async with aiohttp.ClientSession() as session: async with session.get(f'https://pokeapi.co/api/v2/pokemon?limit=151') as response: #cache only works with strings/bytes #we will not change nothing here so no needs to parse json pokemons = await response.text() return pokemons.encode("utf-8") ### # Routes ### def list_original_pokemons(res, req): #check cache for faster response value = cache.get("original_pokemons") if value != None: return res.end(value) #get asynchronous from Model async def get_originals(): value = await cache.run_once("original_pokemons", 5, get_original_pokemons) res.cork_end(value) res.run_async(get_originals()) def list_pokemon(res, req): #get needed parameters try: number = int(req.get_parameter(0)) except: #invalid number return req.set_yield(1) #check cache for faster response cache_key = f"pokemon-{number}" value = cache.get(cache_key) if value != None: return res.end(value) #get asynchronous from Model async def find_pokemon(number, res): #sync with redis lock to run only once #if more than 1 worker/request try to do this request, only one will call the Model and the others will get from cache value = await cache.run_once(cache_key, 5, get_pokemon, number) res.cork_end(value) res.run_async(find_pokemon(number, res)) ### # Here i decided to use an sync first and async only if needs, but you can use async directly see ./async.py ### app = App() app.get("/", list_original_pokemons) app.get("/:number", list_pokemon) app.any("/*", lambda res, _: res.write_status(404).end("Not Found")) app.listen(3000, lambda config: print("Listening on port http://localhost:%d now\n" % config.port)) app.run()