From dbd885c8f5f7c601fd9a03e72c053aabfdf0ec6c Mon Sep 17 00:00:00 2001 From: Igor Lobanov Date: Wed, 23 Nov 2022 12:54:56 +0100 Subject: [PATCH 1/4] uvicorn access logs enabled --- server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.py b/server.py index 2cb70715..dc7041bc 100644 --- a/server.py +++ b/server.py @@ -74,7 +74,7 @@ if __name__ == "__main__": headers=headers, # log_config=LOGGING_CONFIG, log_level=None, - access_log=False, + access_log=True, reload=True ) # , ssl_keyfile="discours.key", ssl_certfile="discours.crt") elif x == "migrate": From 7f3f52c7c9fcb228bd78c477836f3069358569e1 Mon Sep 17 00:00:00 2001 From: Igor Lobanov Date: Wed, 23 Nov 2022 13:22:18 +0100 Subject: [PATCH 2/4] uvicron access logs disabled (no GraphQL playground spam) --- server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.py b/server.py index dc7041bc..2cb70715 100644 --- a/server.py +++ b/server.py @@ -74,7 +74,7 @@ if __name__ == "__main__": headers=headers, # log_config=LOGGING_CONFIG, log_level=None, - access_log=True, + access_log=False, reload=True ) # , ssl_keyfile="discours.key", ssl_certfile="discours.crt") elif x == "migrate": From 82be2da3d89ce709ce5d60f920ac9abf0db7cf67 Mon Sep 17 00:00:00 2001 From: Igor Lobanov Date: Wed, 23 Nov 2022 16:57:22 +0100 Subject: [PATCH 3/4] randomTopics optimization --- resolvers/zine/topics.py | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/resolvers/zine/topics.py b/resolvers/zine/topics.py index b5824fc0..47e6643c 100644 --- a/resolvers/zine/topics.py +++ b/resolvers/zine/topics.py @@ -1,14 +1,15 @@ -import random - -from sqlalchemy import and_ - +import sqlalchemy as sa +from sqlalchemy import and_, select from auth.authenticate import login_required from base.orm import local_session from base.resolvers import mutation, query +from orm import Shout from orm.topic import Topic, TopicFollower from services.zine.topics import TopicStorage from services.stat.reacted import ReactedStorage from services.stat.topicstat import TopicStat + + # from services.stat.viewed import ViewedStorage @@ -98,10 +99,10 @@ async def topic_unfollow(user, slug): with local_session() as session: sub = ( session.query(TopicFollower) - .filter( + .filter( and_(TopicFollower.follower == user.slug, TopicFollower.topic == slug) ) - .first() + .first() ) if not sub: raise Exception("[resolvers.topics] follower not exist") @@ -113,11 +114,8 @@ async def topic_unfollow(user, slug): @query.field("topicsRandom") async def topics_random(_, info, amount=12): - topics = await TopicStorage.get_topics_all() - normalized_topics = [] - for topic in topics: - topic.stat = await get_topic_stat(topic.slug) - if topic.stat["shouts"] > 2: - normalized_topics.append(topic) - sample_length = min(len(normalized_topics), amount) - return random.sample(normalized_topics, sample_length) + with local_session() as session: + q = select(Topic).join(Shout).group_by(Topic.id).having(sa.func.count(Shout.id) > 2).order_by( + sa.func.random()).limit(amount) + random_topics = list(map(lambda result_item: result_item.Topic, session.execute(q))) + return random_topics From 4ef990eadfad2ecc53748473cb1151c8961270c4 Mon Sep 17 00:00:00 2001 From: Igor Lobanov Date: Wed, 23 Nov 2022 22:53:53 +0100 Subject: [PATCH 4/4] loadShouts gotta go fast --- resolvers/zine/load.py | 55 ++++++++++++++++++++++------------------ services/stat/reacted.py | 5 ++-- 2 files changed, 34 insertions(+), 26 deletions(-) diff --git a/resolvers/zine/load.py b/resolvers/zine/load.py index 4f37f9c2..aef3c56e 100644 --- a/resolvers/zine/load.py +++ b/resolvers/zine/load.py @@ -1,6 +1,6 @@ from datetime import datetime, timedelta import sqlalchemy as sa -from sqlalchemy.orm import selectinload +from sqlalchemy.orm import joinedload from sqlalchemy.sql.expression import desc, asc, select, case from base.orm import local_session from base.resolvers import query @@ -37,8 +37,8 @@ async def load_shout(_, info, slug): with local_session() as session: shout = session.query(Shout).options( # TODO add cation - selectinload(Shout.authors), - selectinload(Shout.topics), + joinedload(Shout.authors), + joinedload(Shout.topics), ).filter( Shout.slug == slug ).filter( @@ -48,6 +48,12 @@ async def load_shout(_, info, slug): return shout +def map_result_item(result_item): + shout = result_item[0] + shout.rating = result_item[1] + return shout + + @query.field("loadShouts") async def load_shouts_by(_, info, options): """ @@ -71,14 +77,24 @@ async def load_shouts_by(_, info, options): """ q = select(Shout).options( - # TODO add caption - selectinload(Shout.authors), - selectinload(Shout.topics), + joinedload(Shout.authors), + joinedload(Shout.topics), ).where( Shout.deletedAt.is_(None) ) user = info.context["request"].user q = apply_filters(q, options.get("filters"), user) + q = q.join(Reaction).add_columns(sa.func.sum(case( + (Reaction.kind == ReactionKind.AGREE, 1), + (Reaction.kind == ReactionKind.DISAGREE, -1), + (Reaction.kind == ReactionKind.PROOF, 1), + (Reaction.kind == ReactionKind.DISPROOF, -1), + (Reaction.kind == ReactionKind.ACCEPT, 1), + (Reaction.kind == ReactionKind.REJECT, -1), + (Reaction.kind == ReactionKind.LIKE, 1), + (Reaction.kind == ReactionKind.DISLIKE, -1), + else_=0 + )).label('rating')) o = options.get("order_by") if o: @@ -92,21 +108,9 @@ async def load_shouts_by(_, info, options): ).add_columns( sa.func.max(Reaction.createdAt).label(o) ) - elif o == "rating": - q = q.join(Reaction).add_columns(sa.func.sum(case( - (Reaction.kind == ReactionKind.AGREE, 1), - (Reaction.kind == ReactionKind.DISAGREE, -1), - (Reaction.kind == ReactionKind.PROOF, 1), - (Reaction.kind == ReactionKind.DISPROOF, -1), - (Reaction.kind == ReactionKind.ACCEPT, 1), - (Reaction.kind == ReactionKind.REJECT, -1), - (Reaction.kind == ReactionKind.LIKE, 1), - (Reaction.kind == ReactionKind.DISLIKE, -1), - else_=0 - )).label(o)) order_by = o else: - order_by = 'createdAt' + order_by = Shout.createdAt order_by_desc = True if options.get('order_by_desc') is None else options.get('order_by_desc') @@ -116,10 +120,13 @@ async def load_shouts_by(_, info, options): q = q.group_by(Shout.id).order_by(query_order_by).limit(limit).offset(offset) with local_session() as session: - shouts = list(map(lambda r: r.Shout, session.execute(q))) - for s in shouts: - s.stat = await ReactedStorage.get_shout_stat(s.slug) - for a in s.authors: - a.caption = await ShoutAuthorStorage.get_author_caption(s.slug, a.slug) + shouts = list(map(map_result_item, session.execute(q).unique())) + + for shout in shouts: + shout.stat = await ReactedStorage.get_shout_stat(shout.slug, shout.rating) + + del shout.rating + for author in shout.authors: + author.caption = await ShoutAuthorStorage.get_author_caption(shout.slug, author.slug) return shouts diff --git a/services/stat/reacted.py b/services/stat/reacted.py index 3824ef01..ee3612fd 100644 --- a/services/stat/reacted.py +++ b/services/stat/reacted.py @@ -34,14 +34,15 @@ class ReactedStorage: modified_shouts = set([]) @staticmethod - async def get_shout_stat(slug): + async def get_shout_stat(slug, rating): viewed = int(await ViewedStorage.get_shout(slug)) # print(viewed) return { "viewed": viewed, "reacted": len(await ReactedStorage.get_shout(slug)), "commented": len(await ReactedStorage.get_comments(slug)), - "rating": await ReactedStorage.get_rating(slug), + # "rating": await ReactedStorage.get_rating(slug), + "rating": rating } @staticmethod