Implement Strategy Pattern for the CosmosNetworkStore
Technical Story
When receiving an alert from the Alerter the AlertStore performs the following:
- It stores the alert in
Mongo - Stores the state of the alerted metric inside Redis. This is then used by the
API/UIto display the problems in theOverview Dashboard.
Following the SRP (single responsibility principle) the AlertStore should perform one job only, that being of storing the alert in Mongo. Therefore, we need to create another component which continuously checks the values of each metric and compares them to the alertable thresholds/conditions.
In order to do this change we need to perform the following tasks:
- Remove metric state storing logic from the
AlertStore - Remove internal alerts mechanism as it would no longer be needed
- Develop the
MetricsStateStoreby integrating each monitorable in a granular way using the Strategy pattern
Description
The aim of this ticket is to implement the Strategy Pattern for storing the Cosmos networks' metric state. By using the Strategy Pattern we would be able to easily switch between storing strategies in the MetricStore, depending on what type of transformed data we are receiving
Resources:
- https://refactoring.guru/design-patterns/strategy/python/example
- https://auth0.com/blog/strategy-design-pattern-in-python/
Requirements
To achieve the aims of this ticket you need to implement a strategy that encapsulates the storing of Cosmos network metrics. The following code snippet can be used as an example:
class MetricStateStorer:
"""
This is the Context class, it defines the interface of interest to clients.
"""
def __init__(self, strategy: MetricStateStoringStrategy) -> None:
"""
Usually, the Context accepts a strategy through the constructor, but
also provides a setter to change it at runtime.
"""
self._strategy = strategy
@property
def strategy(self) -> MetricStateStoringStrategy:
"""
The Context maintains a reference to one of the Strategy objects. The
Context does not know the concrete class of a strategy. It should work
with all strategies via the Strategy interface.
"""
return self._strategy
@strategy.setter
def strategy(self, strategy: MetricStateStoringStrategy) -> None:
"""
Usually, the Context allows replacing a Strategy object at runtime.
"""
self._strategy = strategy
def store(self, transformed_data: TransformedData, alerts_config: AlertsConfigs) -> None:
"""
The Context delegates some work to the Strategy object instead of
implementing multiple versions of the algorithm on its own.
"""
self._strategy.store(transformed_data, alerts_config)
class MetricStateStoringStrategy(ABC):
"""
The Strategy interface declares operations common to all supported versions
of some algorithm.
The Context uses this interface to call the algorithm defined by Concrete
Strategies.
"""
@abstractmethod
def store(self, transformed_data: TransformedData, alerts_config: AlertsConfigs) -> None:
pass
class CosmosNetworkMetricStateStoringStrategy(MetricStateStoringStrategy):
def __init__():
redis = Redis('localhost')
def store(self, transformed_data: CosmosNetworkTransformedData, alerts_config: CosmosNetworkAlertsConfigs) -> None:
cosmos_network_metric_state_storing_helper(transformed_data, alerts_config, redis)
Acceptance criteria
Scenario: The CosmosNetworkStore storing procedure should satisfy the Strategy pattern
Another option is to implement the Strategy Pattern on the Existing CosmosNetworkStore and implement two abstract algorithms for the context class, store_metric_state and store_metric_value