diff --git a/resolvers/author.py b/resolvers/author.py index b16c3817..b4eb0314 100644 --- a/resolvers/author.py +++ b/resolvers/author.py @@ -44,20 +44,20 @@ async def get_author(_, _info, slug='', author_id=None): try: if slug: q = select(Author).select_from(Author).filter(Author.slug == slug) - result = get_authors_with_stat_cached(q) + result = await get_authors_with_stat_cached(q) if result: [author] = result author_id = author.id if author_id: - cache = await redis.execute('GET', f'id:{author_id}:author') + cache = await redis.execute('GET', f'author:{author_id}') logger.debug(f'result from cache: {cache}') q = select(Author).where(Author.id == author_id) author_dict = None if cache: author_dict = json.loads(cache) else: - result = get_authors_with_stat_cached(q) + result = await get_authors_with_stat_cached(q) if result: [author] = result author_dict = author.dict() @@ -77,7 +77,7 @@ async def get_author(_, _info, slug='', author_id=None): async def get_author_by_user_id(user_id: str): logger.info(f'getting author id for {user_id}') - redis_key = f'user:{user_id}:author' + redis_key = f'user:{user_id}' author = None try: res = await redis.execute('GET', redis_key) @@ -90,7 +90,7 @@ async def get_author_by_user_id(user_id: str): return author q = select(Author).filter(Author.user == user_id) - result = get_authors_with_stat_cached(q) + result = await get_authors_with_stat_cached(q) if result: [author] = result await set_author_cache(author.dict()) @@ -108,7 +108,7 @@ async def get_author_id(_, _info, user: str): @query.field('load_authors_by') -def load_authors_by(_, _info, by, limit, offset): +async def load_authors_by(_, _info, by, limit, offset): logger.debug(f'loading authors by {by}') q = select(Author) if by.get('slug'): @@ -137,7 +137,7 @@ def load_authors_by(_, _info, by, limit, offset): # q = q.distinct() q = q.limit(limit).offset(offset) - authors = get_authors_with_stat_cached(q) + authors = await get_authors_with_stat_cached(q) return authors @@ -266,7 +266,7 @@ async def get_author_followers(_, _info, slug: str): author_follower_alias.follower == Author.id, ), ) - results = get_authors_with_stat_cached(q) + results = await get_authors_with_stat_cached(q) _ = asyncio.create_task( update_author_followers_cache( author_id, [x.dict() for x in results] @@ -286,6 +286,6 @@ async def get_author_followers(_, _info, slug: str): @query.field('search_authors') -def search_authors(_, _info, what: str): +async def search_authors(_, _info, what: str): q = search(select(Author), what) - return get_authors_with_stat_cached(q) + return await get_authors_with_stat_cached(q) diff --git a/resolvers/follower.py b/resolvers/follower.py index b97e5f98..2fbe3953 100644 --- a/resolvers/follower.py +++ b/resolvers/follower.py @@ -12,7 +12,8 @@ from orm.community import Community from orm.reaction import Reaction from orm.shout import Shout, ShoutReactionsFollower from orm.topic import Topic, TopicFollower -from resolvers.stat import get_authors_with_stat_cached, author_follows_topics, author_follows_authors, get_with_stat +from resolvers.stat import get_authors_with_stat_cached, author_follows_topics, author_follows_authors, get_with_stat, \ + get_topics_with_stat_cached from services.auth import login_required from services.db import local_session from services.cache import ( @@ -34,7 +35,7 @@ async def follow(_, info, what, slug): user_id = info.context.get('user_id') if not user_id: return {"error": "unauthorized"} - [follower] = get_authors_with_stat_cached(select(Author).select_from(Author).filter(Author.user == user_id)) + [follower] = await get_authors_with_stat_cached(select(Author).select_from(Author).filter(Author.user == user_id)) if not follower: return {"error": "cant find follower"} @@ -42,7 +43,7 @@ async def follow(_, info, what, slug): error = author_follow(follower.id, slug) if not error: logger.debug(f'@{follower.slug} followed @{slug}') - [author] = get_authors_with_stat_cached(select(Author).select_from(Author).where(Author.slug == slug)) + [author] = await get_authors_with_stat_cached(select(Author).select_from(Author).where(Author.slug == slug)) if not author: return {"error": "author is not found"} follows = await update_follows_for_author(follower, 'author', author.dict(), True) @@ -52,7 +53,7 @@ async def follow(_, info, what, slug): elif what == 'TOPIC': error = topic_follow(follower.id, slug) if not error: - [topic] = get_with_stat(select(Topic).where(Topic.slug == slug)) + [topic] = await get_topics_with_stat_cached(select(Topic).where(Topic.slug == slug)) if not topic: return {"error": "topic is not found"} follows = await update_follows_for_author(follower, 'topic', topic.dict(), True) @@ -80,7 +81,7 @@ async def unfollow(_, info, what, slug): if not user_id: return {"error": "unauthorized"} follower_query = select(Author).filter(Author.user == user_id) - [follower] = get_authors_with_stat_cached(follower_query) + [follower] = await get_authors_with_stat_cached(follower_query) if not follower: return {"error": "follower profile is not found"} @@ -88,7 +89,7 @@ async def unfollow(_, info, what, slug): error = author_unfollow(follower.id, slug) if not error: logger.info(f'@{follower.slug} unfollowing @{slug}') - [author] = get_authors_with_stat_cached(select(Author).where(Author.slug == slug)) + [author] = await get_authors_with_stat_cached(select(Author).where(Author.slug == slug)) if not author: return {"error": "cant find author"} _followers = await update_followers_for_author(follower, author, False) @@ -99,7 +100,7 @@ async def unfollow(_, info, what, slug): error = topic_unfollow(follower.id, slug) if not error: logger.info(f'@{follower.slug} unfollowing ยง{slug}') - [topic] = get_with_stat(select(Topic).where(Topic.slug == slug)) + [topic] = await get_topics_with_stat_cached(select(Topic).where(Topic.slug == slug)) if not topic: return {"error": "cant find topic"} follows = await update_follows_for_author(follower, 'topic', topic.dict(), False) @@ -123,7 +124,7 @@ async def unfollow(_, info, what, slug): async def get_follows_by_user_id(user_id: str): if not user_id: return {"error": "unauthorized"} - author = await redis.execute('GET', f'user:{user_id}:author') + author = await redis.execute('GET', f'user:{user_id}') if isinstance(author, str): author = json.loads(author) if not author: diff --git a/resolvers/stat.py b/resolvers/stat.py index 123504e6..ea707769 100644 --- a/resolvers/stat.py +++ b/resolvers/stat.py @@ -204,7 +204,21 @@ async def get_authors_with_stat_cached(q): records = [] with local_session() as session: for x in session.execute(q): - stat_str = await redis.execute('GET', f'id:{x.id}:{'author'}') + stat_str = await redis.execute('GET', f'author:{x.id}') + if isinstance(stat_str, str): + x.stat = json.loads(stat_str).get('stat') + records.append(x) + except Exception as exc: + raise Exception(exc) + return records + + +async def get_topics_with_stat_cached(q): + try: + records = [] + with local_session() as session: + for x in session.execute(q): + stat_str = await redis.execute('GET', f'topic:{x.id}') if isinstance(stat_str, str): x.stat = json.loads(stat_str).get('stat') records.append(x) diff --git a/resolvers/topic.py b/resolvers/topic.py index b4d6815b..9ce025a6 100644 --- a/resolvers/topic.py +++ b/resolvers/topic.py @@ -3,25 +3,25 @@ from sqlalchemy import distinct, func, select from orm.author import Author from orm.shout import ShoutTopic from orm.topic import Topic -from resolvers.stat import get_with_stat +from resolvers.stat import get_topics_with_stat_cached from services.auth import login_required from services.db import local_session from services.schema import mutation, query @query.field('get_topics_all') -def get_topics_all(_, _info): - return get_with_stat(select(Topic)) +async def get_topics_all(_, _info): + return await get_topics_with_stat_cached(select(Topic)) @query.field('get_topics_by_community') -def get_topics_by_community(_, _info, community_id: int): +async def get_topics_by_community(_, _info, community_id: int): q = select(Topic).where(Topic.community == community_id) - return get_with_stat(q) + return await get_topics_with_stat_cached(q) @query.field('get_topics_by_author') -def get_topics_by_author(_, _info, author_id=0, slug='', user=''): +async def get_topics_by_author(_, _info, author_id=0, slug='', user=''): q = select(Topic) if author_id: q = q.join(Author).where(Author.id == author_id) @@ -30,13 +30,13 @@ def get_topics_by_author(_, _info, author_id=0, slug='', user=''): elif user: q = q.join(Author).where(Author.user == user) - return get_with_stat(q) + return await get_topics_with_stat_cached(q) @query.field('get_topic') -def get_topic(_, _info, slug: str): +async def get_topic(_, _info, slug: str): q = select(Topic).filter(Topic.slug == slug) - topics = get_with_stat(q) + topics = await get_topics_with_stat_cached(q) if topics: return topics[0] diff --git a/services/cache.py b/services/cache.py index 6e600307..6b946460 100644 --- a/services/cache.py +++ b/services/cache.py @@ -22,8 +22,13 @@ DEFAULT_FOLLOWS = { async def set_author_cache(author: dict): payload = json.dumps(author, cls=CustomJSONEncoder) - await redis.execute("SET", f'user:{author.get("user")}:author', payload) - await redis.execute("SET", f'id:{author.get("id")}:author', payload) + await redis.execute("SET", f'user:{author.get("user")}', payload) + await redis.execute("SET", f'author:{author.get("id")}', payload) + + +async def set_topic_cache(topic: dict): + payload = json.dumps(topic, cls=CustomJSONEncoder) + await redis.execute("SET", f'topic:{topic.get("id")}', payload) async def update_author_followers_cache(author_id: int, followers):