diff options
| author | 2020-11-10 01:14:31 +0100 | |
|---|---|---|
| committer | 2020-11-10 01:14:31 +0100 | |
| commit | c9fe7b1d6b98334c29f516b682b93b4c1c3946a1 (patch) | |
| tree | e2f211a17d250477080f3cbd27de18cad6aac357 | |
| parent | Handle escaped backslashes in strings (diff) | |
Cache user fetched symbols through redis.
| -rw-r--r-- | bot/exts/info/doc/_cog.py | 22 | ||||
| -rw-r--r-- | bot/exts/info/doc/_redis_cache.py | 23 |
2 files changed, 43 insertions, 2 deletions
diff --git a/bot/exts/info/doc/_cog.py b/bot/exts/info/doc/_cog.py index 257435e95..ab3ad159a 100644 --- a/bot/exts/info/doc/_cog.py +++ b/bot/exts/info/doc/_cog.py @@ -4,6 +4,7 @@ import asyncio import logging import re import sys +import urllib.parse from collections import defaultdict from contextlib import suppress from typing import Dict, List, NamedTuple, Optional, Union @@ -21,6 +22,7 @@ from bot.utils.messages import wait_for_deletion from bot.utils.scheduling import Scheduler from ._inventory_parser import FAILED_REQUEST_ATTEMPTS, fetch_inventory from ._parsing import get_symbol_markdown +from ._redis_cache import DocRedisCache log = logging.getLogger(__name__) @@ -182,6 +184,8 @@ class InventoryURL(commands.Converter): class DocCog(commands.Cog): """A set of commands for querying & displaying documentation.""" + doc_cache = DocRedisCache() + def __init__(self, bot: Bot): self.base_urls = {} self.bot = bot @@ -296,16 +300,30 @@ class DocCog(commands.Cog): Attempt to scrape and fetch the data for the given `symbol`, and build an embed from its contents. If the symbol is known, an Embed with documentation about it is returned. + + First check the DocRedisCache before querying the cog's `CachedParser`, + if not present also create a redis entry for the symbol. """ + log.trace(f"Building embed for symbol `{symbol}`") symbol_info = self.doc_symbols.get(symbol) if symbol_info is None: + log.debug("Symbol does not exist.") return None self.bot.stats.incr(f"doc_fetches.{symbol_info.package.lower()}") + item_url = f"{symbol_info.url}#{symbol_info.symbol_id}" + redis_key = "".join(urllib.parse.urlparse(item_url)[1:]) # url without scheme + + markdown = await self.doc_cache.get(redis_key) + if markdown is None: + log.debug(f"Redis cache miss for symbol `{symbol}`.") + markdown = await self.item_fetcher.get_markdown(self.bot.http_session, symbol_info) + await self.doc_cache.set(redis_key, markdown) + embed = discord.Embed( title=discord.utils.escape_markdown(symbol), - url=f"{symbol_info.url}#{symbol_info.symbol_id}", - description=await self.item_fetcher.get_markdown(self.bot.http_session, symbol_info) + url=item_url, + description=markdown ) # Show all symbols with the same name that were renamed in the footer. embed.set_footer( diff --git a/bot/exts/info/doc/_redis_cache.py b/bot/exts/info/doc/_redis_cache.py new file mode 100644 index 000000000..147394ba6 --- /dev/null +++ b/bot/exts/info/doc/_redis_cache.py @@ -0,0 +1,23 @@ +from typing import Optional + +from async_rediscache.types.base import RedisObject, namespace_lock + + +class DocRedisCache(RedisObject): + """Interface for redis functionality needed by the Doc cog.""" + + @namespace_lock + async def set(self, key: str, value: str) -> None: + """ + Set markdown `value` for `key`. + + Keys expire after a week to keep data up to date. + """ + with await self._get_pool_connection() as connection: + await connection.setex(f"{self.namespace}:{key}", 7*24*60*60, value) + + @namespace_lock + async def get(self, key: str) -> Optional[str]: + """Get markdown contents for `key`.""" + with await self._get_pool_connection() as connection: + return await connection.get(f"{self.namespace}:{key}", encoding="utf8") |