From 88525276c286c4cd8d1d6e1af91ecb50814685fb Mon Sep 17 00:00:00 2001 From: Untone Date: Sat, 25 Jan 2025 11:23:20 +0300 Subject: [PATCH] cache-invalidate-fix --- orm/shout.py | 46 ++++++++++++++++++++++----------------------- resolvers/editor.py | 17 ++++------------- resolvers/reader.py | 18 +++++++++--------- 3 files changed, 36 insertions(+), 45 deletions(-) diff --git a/orm/shout.py b/orm/shout.py index 008826fd..5ed3db61 100644 --- a/orm/shout.py +++ b/orm/shout.py @@ -41,34 +41,34 @@ class ShoutAuthor(Base): class Shout(Base): __tablename__ = "shout" - created_at = Column(Integer, nullable=False, default=lambda: int(time.time())) - updated_at = Column(Integer, nullable=True, index=True) - published_at = Column(Integer, nullable=True, index=True) - featured_at = Column(Integer, nullable=True, index=True) - deleted_at = Column(Integer, nullable=True, index=True) + created_at: int = Column(Integer, nullable=False, default=lambda: int(time.time())) + updated_at: int | None = Column(Integer, nullable=True, index=True) + published_at: int | None = Column(Integer, nullable=True, index=True) + featured_at: int | None = Column(Integer, nullable=True, index=True) + deleted_at: int | None = Column(Integer, nullable=True, index=True) - created_by = Column(ForeignKey("author.id"), nullable=False) - updated_by = Column(ForeignKey("author.id"), nullable=True) - deleted_by = Column(ForeignKey("author.id"), nullable=True) - community = Column(ForeignKey("community.id"), nullable=False) + created_by: int = Column(ForeignKey("author.id"), nullable=False) + updated_by: int | None = Column(ForeignKey("author.id"), nullable=True) + deleted_by: int | None = Column(ForeignKey("author.id"), nullable=True) + community: int = Column(ForeignKey("community.id"), nullable=False) - body = Column(String, nullable=False, comment="Body") - slug = Column(String, unique=True) - cover = Column(String, nullable=True, comment="Cover image url") - cover_caption = Column(String, nullable=True, comment="Cover image alt caption") - lead = Column(String, nullable=True) - description = Column(String, nullable=True) - title = Column(String, nullable=False) - subtitle = Column(String, nullable=True) - layout = Column(String, nullable=False, default="article") - media = Column(JSON, nullable=True) + body: str = Column(String, nullable=False, comment="Body") + slug: str = Column(String, unique=True) + cover: str | None = Column(String, nullable=True, comment="Cover image url") + cover_caption: str | None = Column(String, nullable=True, comment="Cover image alt caption") + lead: str | None = Column(String, nullable=True) + description: str | None = Column(String, nullable=True) + title: str = Column(String, nullable=False) + subtitle: str | None = Column(String, nullable=True) + layout: str = Column(String, nullable=False, default="article") + media: dict | None = Column(JSON, nullable=True) authors = relationship(Author, secondary="shout_author") topics = relationship(Topic, secondary="shout_topic") reactions = relationship(Reaction) - lang = Column(String, nullable=False, default="ru", comment="Language") - version_of = Column(ForeignKey("shout.id"), nullable=True) - oid = Column(String, nullable=True) + lang: str = Column(String, nullable=False, default="ru", comment="Language") + version_of: int | None = Column(ForeignKey("shout.id"), nullable=True) + oid: str | None = Column(String, nullable=True) - seo = Column(String, nullable=True) # JSON + seo: str | None = Column(String, nullable=True) # JSON diff --git a/resolvers/editor.py b/resolvers/editor.py index 02ac6327..19a9474b 100644 --- a/resolvers/editor.py +++ b/resolvers/editor.py @@ -4,7 +4,7 @@ from sqlalchemy import and_, desc, select from sqlalchemy.orm import joinedload from sqlalchemy.sql.functions import coalesce -from cache.cache import cache_author, cache_topic, invalidate_shouts_cache +from cache.cache import cache_author, cache_topic, invalidate_shouts_cache, invalidate_shout_related_cache from orm.author import Author from orm.shout import Shout, ShoutAuthor, ShoutTopic from orm.topic import Topic @@ -322,11 +322,8 @@ async def update_shout(_, info, shout_id: int, shout_input=None, publish=False): shout_input["updated_at"] = current_time if publish: - logger.info(f"Publishing shout#{shout_id}") - logger.debug(f"Before update: published_at={shout_by_id.published_at}") + logger.info(f"publishing shout#{shout_id} with input: {shout_input}") shout_input["published_at"] = current_time - Shout.update(shout_by_id, shout_input) - logger.debug(f"After update: published_at={shout_by_id.published_at}") Shout.update(shout_by_id, shout_input) session.add(shout_by_id) session.commit() @@ -344,19 +341,13 @@ async def update_shout(_, info, shout_id: int, shout_input=None, publish=False): "unrated", # неоцененные ] - # Добавляем ключи для старых тем (до обновления) + # Добавляем ключи для тем публикации for topic in shout_by_id.topics: cache_keys.append(f"topic_{topic.id}") cache_keys.append(f"topic_shouts_{topic.id}") - # Добавляем ключи для новых тем (если есть в shout_input) - if shout_input.get("topics"): - for topic in shout_input["topics"]: - if topic.get("id"): - cache_keys.append(f"topic_{topic.id}") - cache_keys.append(f"topic_shouts_{topic.id}") - await invalidate_shouts_cache(cache_keys) + await invalidate_shout_related_cache(shout_by_id, author_id) # Обновляем кэш тем и авторов for topic in shout_by_id.topics: diff --git a/resolvers/reader.py b/resolvers/reader.py index 698b11ab..0f5beaf9 100644 --- a/resolvers/reader.py +++ b/resolvers/reader.py @@ -330,7 +330,9 @@ def apply_sorting(q, options): order_str = options.get("order_by") if order_str in ["rating", "comments_count", "last_commented_at"]: query_order_by = desc(text(order_str)) if options.get("order_by_desc", True) else asc(text(order_str)) - q = q.distinct(text(order_str), Shout.id).order_by(nulls_last(query_order_by), Shout.id) + q = q.distinct(text(order_str), Shout.id).order_by( # DISTINCT ON включает поле сортировки + nulls_last(query_order_by), Shout.id + ) else: q = q.distinct(Shout.published_at, Shout.id).order_by(Shout.published_at.desc(), Shout.id) @@ -341,21 +343,19 @@ def apply_sorting(q, options): async def load_shouts_by(_, info: GraphQLResolveInfo, options): """ Загрузка публикаций с фильтрацией, сортировкой и пагинацией. + + :param _: Корневой объект запроса (не используется) + :param info: Информация о контексте GraphQL + :param options: Опции фильтрации и сортировки + :return: Список публикаций, удовлетворяющих критериям """ # Базовый запрос со статистикой q = query_with_stat(info) - logger.debug(f"Base query created with options: {options}") # Применяем остальные опции фильтрации q, limit, offset = apply_options(q, options) - # Логируем SQL запрос для отладки - from sqlalchemy.dialects import postgresql - - sql = q.compile(dialect=postgresql.dialect(), compile_kwargs={"literal_binds": True}) - logger.debug(f"Final SQL query: {sql}") - - # Передача сформированного запроса в метод получения публикаций + # Передача сформированного запроса в метод получения публикаций с учетом сортировки и пагинации return get_shouts_with_links(info, q, limit, offset)