This repository implements a Pager system using Hexagonal Architecture principles. The system is designed to handle alerts and notifications for monitored services.
The Hexagonal Pager system is built to manage and escalate alerts for various monitored services. It uses DDD to model the core business logic and Hexagonal Architecture to ensure the system is modular, testable, and adaptable to different technologies and interfaces.
The Domain Layer contains the core business logic and domain models. It is independent of any external systems or frameworks. This layer is the heart of the application, encapsulating the business rules and ensuring that the system behaves correctly.
- Models: Represent the core entities and value objects in the system.
EscalationPolicy
: Defines the rules for escalating alerts.MonitoredService
: Represents a service being monitored.NotificationTarget
: Represents the target to be notified.
- Events: Define the domain events that occur within the system.
Alert
: Triggered when an alert is raised.Acknowledgement
: Triggered when an alert is acknowledged.HealthyEvent
: Triggered when a service is healthy.Timeout
: Triggered when an alert times out.
- Services: Contain the business logic and domain services.
PagerService
: Handles the core logic for managing alerts and notifications.
The Application Layer orchestrates the use cases and application logic. It interacts with the Domain Layer to fulfill the application's requirements. This layer is responsible for coordinating the application activities and ensuring that the use cases are executed correctly.
- Application Services: Implement the use cases of the application.
PagerApplicationService
: Coordinates the alerting process and interacts with the domain services.
The Ports Layer defines the interfaces for the external systems and services that the application interacts with. This layer acts as a boundary, ensuring that the core application logic remains decoupled from the external systems.
- EmailSender: Interface for sending emails.
EmailSender
: Defines the contract for sending email notifications.
- SmsSender: Interface for sending SMS.
SmsSender
: Defines the contract for sending SMS notifications.
- EscalationPolicyRepository: Interface for accessing escalation policies.
EscalationPolicyRepository
: Defines the contract for accessing escalation policies.
Ommited for now.
The Adapters Layer implements the interfaces defined in the Ports Layer. It adapts the external systems and services to the application's requirements. This layer is responsible for translating the data and interactions between the application and the external systems.
Clone the repository:
git clone https://github.com/talaman/hexagonal-pager.git
cd hexagonal-pager
I have included a vscode devcontainer configuration to make it easier to get started with the project. If you have vscode, the Dev Containers extension and Docker installed, you can open the project in a container and have all the dependencies set up automatically.
Just open the project in vscode and click on the "Reopen in Container" button when prompted.
When the container is ready, you can run the tests using the following command in the terminal:
pytest
Otherwise, get your preferred Python environment set up, I have used 3.12 for this project.
Install the dependencies:
pip install -r requirements.txt
When the dependencies are installed, you can run the tests using the following command in the terminal:
pytest
As a production-ready application, the Pager can be packaged as a Docker image and run in a containerized environment. This is automated with the CI pipeline, but here is an example of how to build and run the application with Docker:
- Build the Docker image:
docker build -t hexagonal-pager .
- Test the application:
docker run --rm hexagonal-pager pytest
- Run the application:
This is an example of how to run the application. But a real application would have an adapter layer to interact with external systems.
docker run -d hexagonal-pager
Then you can push the image to a container registry and deploy it to your preferred container orchestration platform.
This project uses GitHub Actions for continuous integration. The CI pipeline is defined in .github/workflows/ci.yml
and it runs tests in 2 different environments: Github hosted runners and Docker.
It includes the following steps:
- Checkout code: Uses the actions/checkout@v3 action to checkout the code.
- Set up Python: Uses the actions/setup-python@v4 action to set up Python 3.12.
- Install dependencies: Installs the required dependencies using pip.
- Run tests: Runs the tests using pytest.
- Build and export to Docker: Uses the docker/build-push-action@v6 action to build and export the Docker image.
The CI pipeline is triggered on every push or pull request to the main branch, and runs the tests to ensure the code quality and functionality.
- Implement the Adapters Layer to integrate with external systems.
- Add more use cases and scenarios to cover additional functionalities.
- Ensure the Pager Service handles concurrency issues, such as preventing multiple notifications to the same target when multiple alerts are received simultaneously.
- Define the expected guarantees from the database regarding consistency and reliability.
- Implement a robust test strategy to cover all edge cases and concurrency scenarios.