From 2b89ab7c7818b2ad7fb79b25f0163cbfc5ae16ef Mon Sep 17 00:00:00 2001 From: Untone Date: Wed, 6 Mar 2024 21:57:04 +0300 Subject: [PATCH] custom-encoder-fix --- resolvers/author.py | 9 +++++---- services/cache.py | 11 ++++++----- services/encoders.py | 9 +++++++++ services/search.py | 3 ++- 4 files changed, 22 insertions(+), 10 deletions(-) create mode 100644 services/encoders.py diff --git a/resolvers/author.py b/resolvers/author.py index 5a3a2f9f..0f6f556f 100644 --- a/resolvers/author.py +++ b/resolvers/author.py @@ -13,6 +13,7 @@ from resolvers.stat import get_with_stat, author_follows_authors, author_follows from services.cache import set_author_cache, update_author_followers_cache from services.auth import login_required from services.db import local_session +from services.encoders import CustomJSONEncoder from services.rediscache import redis from services.schema import mutation, query from services.logger import root_logger as logger @@ -161,14 +162,14 @@ async def get_author_follows(_, _info, slug='', user=None, author_id=None): ) if not cached: prepared = [author.dict() for author in authors] - await redis.execute('SETEX', rkey, 24 * 60 * 60, json.dumps(prepared)) + await redis.execute('SET', rkey, 24 * 60 * 60, json.dumps(prepared), cls=CustomJSONEncoder) rkey = f'author:{author_id}:follows-topics' cached = await redis.execute('GET', rkey) topics = json.loads(cached) if cached else author_follows_topics(author_id) if not cached: prepared = [topic.dict() for topic in topics] - await redis.execute('SETEX', rkey, 24 * 60 * 60, json.dumps(prepared)) + await redis.execute('SET', rkey, 24 * 60 * 60, json.dumps(prepared), cls=CustomJSONEncoder) return { 'topics': topics, 'authors': authors, @@ -197,7 +198,7 @@ async def get_author_follows_topics(_, _info, slug='', user=None, author_id=None topics = json.loads(cached) if cached else author_follows_topics(author_id) if not cached: prepared = [topic.dict() for topic in topics] - await redis.execute('SETEX', rkey, 24 * 60 * 60, json.dumps(prepared)) + await redis.execute('SET', rkey, 24 * 60 * 60, json.dumps(prepared), cls=CustomJSONEncoder) return topics else: raise ValueError('Author not found') @@ -222,7 +223,7 @@ async def get_author_follows_authors(_, _info, slug='', user=None, author_id=Non ) if not cached: prepared = [author.dict() for author in authors] - await redis.execute('SETEX', rkey, 24 * 60 * 60, json.dumps(prepared)) + await redis.execute('SET', rkey, 24 * 60 * 60, json.dumps(prepared), cls=CustomJSONEncoder) return authors else: raise ValueError('Author not found') diff --git a/services/cache.py b/services/cache.py index 74e5f943..ec806138 100644 --- a/services/cache.py +++ b/services/cache.py @@ -8,6 +8,7 @@ from orm.reaction import Reaction from orm.shout import ShoutAuthor, Shout from orm.topic import Topic, TopicFollower from resolvers.stat import get_with_stat +from services.encoders import CustomJSONEncoder from services.rediscache import redis from services.logger import root_logger as logger @@ -21,19 +22,19 @@ DEFAULT_FOLLOWS = { async def set_author_cache(author: dict, ttl=25 * 60 * 60): payload = json.dumps(author) - await redis.execute('SETEX', f'user:{author.get("user")}:author', ttl, payload) - await redis.execute('SETEX', f'id:{author.get("id")}:author', ttl, payload) + await redis.execute('SET', f'user:{author.get("user")}:author', ttl, payload, cls=CustomJSONEncoder) + await redis.execute('SET', f'id:{author.get("id")}:author', ttl, payload, cls=CustomJSONEncoder) async def update_author_followers_cache(author_id: int, followers, ttl=25 * 60 * 60): payload = json.dumps(followers) - await redis.execute('SETEX', f'author:{author_id}:followers', ttl, payload) + await redis.execute('SET', f'author:{author_id}:followers', ttl, payload, cls=CustomJSONEncoder) async def set_follows_topics_cache(follows, author_id: int, ttl=25 * 60 * 60): try: payload = json.dumps(follows) - await redis.execute('SETEX', f'author:{author_id}:follows-topics', ttl, payload) + await redis.execute('SET', f'author:{author_id}:follows-topics', ttl, payload, cls=CustomJSONEncoder) except Exception as exc: logger.error(exc) import traceback @@ -46,7 +47,7 @@ async def set_follows_authors_cache(follows, author_id: int, ttl=25 * 60 * 60): try: payload = json.dumps(follows) await redis.execute( - 'SETEX', f'author:{author_id}:follows-authors', ttl, payload + 'SET', f'author:{author_id}:follows-authors', ttl, payload, cls=CustomJSONEncoder ) except Exception: import traceback diff --git a/services/encoders.py b/services/encoders.py new file mode 100644 index 00000000..fe4c97d4 --- /dev/null +++ b/services/encoders.py @@ -0,0 +1,9 @@ +import json +from decimal import Decimal + + +class CustomJSONEncoder(json.JSONEncoder): + def default(self, obj): + if isinstance(obj, Decimal): + return str(obj) + return super().default(obj) diff --git a/services/search.py b/services/search.py index f9efc3e1..b5c81169 100644 --- a/services/search.py +++ b/services/search.py @@ -4,6 +4,7 @@ import os from opensearchpy import OpenSearch +from services.encoders import CustomJSONEncoder from services.logger import root_logger as logger from services.rediscache import redis @@ -144,7 +145,7 @@ class SearchService: # Use Redis as cache with TTL redis_key = f'search:{text}' - await redis.execute('SETEX', redis_key, REDIS_TTL, json.dumps(results)) + await redis.execute('SETEX', redis_key, REDIS_TTL, json.dumps(results), cls=CustomJSONEncoder) return []