fix: add async cache to async operations and sync cache (stdlib) for sync operations

This commit is contained in:
austnv
2026-06-14 23:23:05 +03:00
parent 5d221415cc
commit ccf99af7e1
4 changed files with 39 additions and 17 deletions
+1
View File
@@ -6,6 +6,7 @@ readme = "README.md"
requires-python = ">=3.12" requires-python = ">=3.12"
dependencies = [ dependencies = [
"aiofiles>=25.1.0", "aiofiles>=25.1.0",
"async-lru>=2.3.0",
"bs4>=0.0.2", "bs4>=0.0.2",
"fastapi>=0.136.3", "fastapi>=0.136.3",
"httpx>=0.28.1", "httpx>=0.28.1",
+18 -9
View File
@@ -3,12 +3,15 @@ from typing import Optional, Dict, Any, Tuple
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
from fastapi import APIRouter, Request from fastapi import APIRouter, Request
from functools import lru_cache
from httpx import AsyncClient from httpx import AsyncClient
from async_lru import alru_cache
from functools import lru_cache
import asyncio
import logging import logging
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)
@@ -64,6 +67,7 @@ class IPInfo:
def __init__(self, html: str): def __init__(self, html: str):
self._data = self._parse(html) self._data = self._parse(html)
@lru_cache(maxsize=1000)
def _parse(self, html: str) -> Optional[IPInfoModel]: def _parse(self, html: str) -> Optional[IPInfoModel]:
"""Парсит HTML и возвращает модель""" """Парсит HTML и возвращает модель"""
soup = BeautifulSoup(html, 'html.parser') soup = BeautifulSoup(html, 'html.parser')
@@ -168,7 +172,14 @@ class IPInfo:
router = APIRouter(prefix='/api/v1', tags=['ip']) router = APIRouter(prefix='/api/v1', tags=['ip'])
@lru_cache @alru_cache(maxsize=1000, ttl=86400)
async def get_ip_info(ip: str, user_agent: str):
"""Асинхронная функция для получения информации об IP с кешированием."""
async with AsyncClient(headers={'User-Agent': user_agent}) as client:
response = await client.get(f'https://ipinfo.io/{ip}')
return response.text
@router.get('/ip') @router.get('/ip')
async def get_ip(request: Request): async def get_ip(request: Request):
forwarded = request.headers.get('X-Forwarded-For') forwarded = request.headers.get('X-Forwarded-For')
@@ -180,11 +191,9 @@ async def get_ip(request: Request):
else: else:
client_ip = request.client.host client_ip = request.client.host
async with AsyncClient(headers={'User-Agent': user_agent}) as client: html = await get_ip_info(client_ip, user_agent)
response = await client.get(f'https://ipinfo.io/{client_ip}')
html = response.text
ipinfo = IPInfo(html)
logging.info(ipinfo._data)
return ipinfo.dict() result = await asyncio.to_thread(lambda: IPInfo(html).dict())
logging.info(result)
return result
+8 -7
View File
@@ -1,15 +1,16 @@
from fastapi import APIRouter from fastapi import APIRouter
from functools import lru_cache import aiofiles
import json import json
import asyncio from async_lru import alru_cache
router = APIRouter(prefix='/api/v1', tags=['tariffs']) router = APIRouter(prefix='/api/v1', tags=['tariffs'])
@lru_cache(maxsize=1) @alru_cache(maxsize=1, ttl=86400)
def get_tariffs_sync(): async def get_tariffs_sync():
with open('data/tariffs.json', 'r', encoding='utf-8') as f: async with aiofiles.open('data/tariffs.json', 'r', encoding='utf-8') as f:
return json.load(f) content = await f.read()
return json.loads(content)
@router.get('/tariffs') @router.get('/tariffs')
async def get_tariffs(): async def get_tariffs():
return await asyncio.to_thread(get_tariffs_sync) return await get_tariffs_sync()
Generated
+12 -1
View File
@@ -47,6 +47,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl", hash = "sha256:08b310f9e24a9594186fd75b4f73f4a4152069e3853f1ed8bfbf58369f4ad708", size = 114353, upload-time = "2026-03-24T12:59:08.246Z" }, { url = "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl", hash = "sha256:08b310f9e24a9594186fd75b4f73f4a4152069e3853f1ed8bfbf58369f4ad708", size = 114353, upload-time = "2026-03-24T12:59:08.246Z" },
] ]
[[package]]
name = "async-lru"
version = "2.3.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/e8/1f/989ecfef8e64109a489fff357450cb73fa73a865a92bd8c272170a6922c2/async_lru-2.3.0.tar.gz", hash = "sha256:89bdb258a0140d7313cf8f4031d816a042202faa61d0ab310a0a538baa1c24b6", size = 16332, upload-time = "2026-03-19T01:04:32.413Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e5/e2/c2e3abf398f80732e58b03be77bde9022550d221dd8781bf586bd4d97cc1/async_lru-2.3.0-py3-none-any.whl", hash = "sha256:eea27b01841909316f2cc739807acea1c623df2be8c5cfad7583286397bb8315", size = 8403, upload-time = "2026-03-19T01:04:30.883Z" },
]
[[package]] [[package]]
name = "beautifulsoup4" name = "beautifulsoup4"
version = "4.15.0" version = "4.15.0"
@@ -889,10 +898,11 @@ wheels = [
[[package]] [[package]]
name = "uvpn-backend" name = "uvpn-backend"
version = "0.1.0" version = "0.2.0"
source = { virtual = "." } source = { virtual = "." }
dependencies = [ dependencies = [
{ name = "aiofiles" }, { name = "aiofiles" },
{ name = "async-lru" },
{ name = "bs4" }, { name = "bs4" },
{ name = "fastapi" }, { name = "fastapi" },
{ name = "httpx" }, { name = "httpx" },
@@ -907,6 +917,7 @@ dev = [
[package.metadata] [package.metadata]
requires-dist = [ requires-dist = [
{ name = "aiofiles", specifier = ">=25.1.0" }, { name = "aiofiles", specifier = ">=25.1.0" },
{ name = "async-lru", specifier = ">=2.3.0" },
{ name = "bs4", specifier = ">=0.0.2" }, { name = "bs4", specifier = ">=0.0.2" },
{ name = "fastapi", specifier = ">=0.136.3" }, { name = "fastapi", specifier = ">=0.136.3" },
{ name = "httpx", specifier = ">=0.28.1" }, { name = "httpx", specifier = ">=0.28.1" },