init comment-service

This commit is contained in:
2023-09-27 16:05:24 +01:00
parent 0ae3ee3af4
commit 55a533c461
41 changed files with 2800 additions and 0 deletions

View File

@@ -0,0 +1,76 @@
import pickle
import logging
from typing import Type, List
import redis.asyncio as redis
from comment_service.models.service import CommentRepository, Comment, CommentCreate, CommentUpdate
class ServiceRedisRepository(CommentRepository):
"""The Redis repository is responsible for caching
requests to help reduce the amount of database calls,
allowing for faster data access.
If the Redis repository does not have the data cached,
or does not cache data for that request, then the call is
passed downstream to the database repository.
Attributes:
_conn (redis.asyncio.redis.Redis): The Redis connection.
_repo (CommentRepository): The next downstream repository (the DB repo).
"""
def __init__(self, redis_conn: redis.Redis, downstream_repo: Type[CommentRepository]) -> None:
self._conn = redis_conn
self._repo = downstream_repo
async def _purge_cached_comments(self, post_id: str) -> None:
try:
self._conn.delete(post_id)
except Exception:
pass
async def get_comment(self, comment_id: int) -> Comment:
return await self._repo.get_comment(comment_id)
async def get_post_comments(self, post_id: str) -> List[Comment]:
post_id = post_id.lower()
failure = False
try:
# check for a cached version of the post comments
response = await self._conn.get(post_id)
if response is not None:
comments = pickle.loads(response)
assert type(comments) == list
return comments
except Exception as e:
failure = True
logging.error("Redis Repo: error whilst getting post comments", e)
pass
comments = await self._repo.get_post_comments(post_id)
if failure is False:
# cache the retrieved comments
try:
await self._conn.set(post_id, pickle.dumps(comments), ex=120) # TTL: 2 minutes
except Exception:
logging.error("Redis Repo: error whilst caching post comments", e)
pass
return comments
async def create_comment(self, data: CommentCreate) -> Comment:
comment = await self._repo.create_comment(data)
await self._purge_cached_comments(comment.post_id)
return comment
async def update_comment(self, comment_id: int, data: CommentUpdate) -> Comment:
comment = await self._repo.update_comment(comment_id, data)
await self._purge_cached_comments(comment.post_id)
return comment
async def delete_comment(self, comment_id: int) -> None:
# todo: purge cache of comments on post (instead of waiting for TTL expiry)
await self._repo.delete_comment(comment_id)

View File

@@ -0,0 +1,48 @@
from typing import Type
import redis.asyncio as redis
from comment_service.models.config import Config
from comment_service.models.service import CommentRepository
from comment_service.redis.repository import ServiceRedisRepository
async def connect_redis(config: Config) -> redis.Redis:
"""Opens a connection to Redis.
Args:
config (Config): The app configuration.
Returns:
A connected redis.Redis instance
"""
host, port = config.redis_host, 5432
try:
host, port = config.redis_host.split(":")
port = int(port)
except Exception:
pass
conn = redis.Redis(host=host, port=port, password=config.redis_pass)
await conn.ping()
return conn
async def create_redis_repository(config: Config, downstream_repo: Type[CommentRepository]) -> ServiceRedisRepository:
"""Create the Redis repository.
Open a Redis connection and instantialise the
Redis repository.
Args:
downstream_repo (Type[CommentRepository]): The next downstream repository
that will be called by the Redis repository. (in this case the database
repository)
Returns:
ServiceRedisRepository
"""
redis_conn = await connect_redis(config)
return ServiceRedisRepository(redis_conn=redis_conn, downstream_repo=downstream_repo)