init auth-service

This commit is contained in:
2023-09-27 16:01:41 +01:00
parent 7192f11059
commit 0ae3ee3af4
40 changed files with 2616 additions and 2 deletions

View File

@@ -0,0 +1,80 @@
import logging
from typing import Type
from google.protobuf import message
from aiokafka import AIOKafkaConsumer
from aiokafka.structs import ConsumerRecord
from auth_service.models.config import Config
from auth_service.models.service import AuthDBRepository
class EventConsumer:
"""An abstract consumer base class.
Attributes:
CONSUMER_TOPIC: The topic to consume events from.
CONSUMER_EVENT_TYPE (Type[message.Message]): The protobuf class type of the event msgs (used for deserialisation).
_db_repo (Type[AuthDBRepository]): The repository interface for modifying data.
_consumer (aiokafka.AIOKafkaConsumer): The underlying Kafka instance.
"""
CONSUMER_TOPIC: str
CONSUMER_EVENT_TYPE: Type[message.Message]
def __init__(self, config: Config, db_repo: Type[AuthDBRepository]) -> None:
"""Initialise the event consumer.
Args:
config (Config): The app configuration instance (to access brokers list).
db_repo (Type[AuthDBRepository]): The repository interface for updating data.
"""
self._db_repo = db_repo
self._consumer = AIOKafkaConsumer(
self.CONSUMER_TOPIC,
bootstrap_servers=config.kafka_brokers,
group_id="auth-service"
)
async def start(self) -> None:
"""Begin consuming messages."""
await self._consumer.start()
try:
async for msg in self._consumer:
await self._process_msg(msg)
except Exception as e:
logging.error(f"error whilst consuming messages (on topic '{self.CONSUMER_TOPIC}'): {e}")
finally:
await self._consumer.stop()
async def _process_msg(self, msg: ConsumerRecord) -> None:
"""Process a recieved message.
The messages are deserialise from bytes into their protobuf form,
then passed to the `_process_event` method to handle the logic.
Args:
msg (kafka.Message): The event to process.
"""
try:
event = self.CONSUMER_EVENT_TYPE()
event.ParseFromString(msg.value)
assert event.type != ""
await self._process_event(event)
except AssertionError:
logging.error("invalid event recieved")
return
except Exception as e:
logging.error("error whilst processing recieved event:", e)
return
async def _process_event(self, event: Type[message.Message]) -> None:
"""Process a recieved event.
Args:
event (Type[message.Message]): The event serialised to protobuf form.
"""
raise NotImplementedError("required consumer method (_process_event) not implemented")

View File

@@ -0,0 +1,42 @@
from typing import Type
from auth_service.models.config import Config
from auth_service.models.service import AuthDBRepository
from auth_service.events.user_consumer import UserEventConsumer
class EventConsumersWrapper:
"""A wrapper class for starting the event consumers.
Attributes:
_user_consumer (UserEventConsumer): Wrapped consumer.
"""
def __init__(self, user_consumer: UserEventConsumer) -> None:
"""Add the consumers to the wrapper
Args:
user_consumer (UserEventConsumer): Initialised user consumer.
"""
self._user_consumer = user_consumer
async def start(self) -> None:
"""Begin consuming events on all the event consumers."""
await self._user_consumer.start()
def create_consumers(config: Config, db_repo: Type[AuthDBRepository]) -> EventConsumersWrapper:
"""Initialse the event consumers and return them in a wrapper.
Args:
config (Config): The app configuration instance.
db_repo (Type[AuthDBRepository]): The database repo to pass to the consumers.
Returns:
EventConsumerWrapper
"""
user_consumer = UserEventConsumer(config, db_repo)
return EventConsumersWrapper(user_consumer=user_consumer)

View File

@@ -0,0 +1,32 @@
import logging
from auth_service.models.proto import user_pb2
from auth_service.events.base_consumer import EventConsumer
class UserEventConsumer(EventConsumer):
"""Consumer class responsible for 'user' events.
Attributes:
CONSUMER_TOPIC: The topic to consume events from.
CONSUMER_EVENT_TYPE (user_pb2.UserEvent): Kafka messages are serialised to this type.
_db_repo (AuthDBRepository): The repository interface for modifying data.
_consumer (aiokafka.AIOKafkaConsumer): The underlying Kafka instance.
"""
CONSUMER_TOPIC = "user"
CONSUMER_EVENT_TYPE = user_pb2.UserEvent
async def _process_event(self, event: user_pb2.UserEvent) -> None:
"""Process a recieved event.
In response to a User deleted event, delete any auth methods
this service has in relation to that user.
Args:
event (user_pb2.UserEvent): The decoded protobuf message.
"""
if event.type == "deleted":
await self._db_repo.delete_password_auth_method(event.data.id)
logging.info("succesfully processed UserEvent (type: 'deleted')")