A Slim Framework 4 application for monitoring GitHub repository releases and sending notifications.
- Docker & Docker Compose (recommended)
git clone https://github.com/DimaMaimesko/repo-observer.git
cd repo-observercp .env.example .envdocker-compose up -ddocker-compose exec slim composer installdocker-compose exec slim php vendor/bin/doctrine-migrations migrate --no-interactionAPI Key: secret-api-key
Application web interface: http://localhost:8081
MailPit (Email viewer): http://localhost:8025
Prometheus metrics: http://localhost:8081/metrics
JSON-RPC 2.0 API playground: http://localhost:8081/openrpc-playground.html
JSON-RPC 2.0 API spec: http://localhost:8081/openrpc-spec.json
API Key: secret-api-key
Application web interface: http://ec2-18-215-163-188.compute-1.amazonaws.com
Prometheus metrics: http://ec2-18-215-163-188.compute-1.amazonaws.com/metrics
JSON-RPC 2.0 API playground: http://ec2-18-215-163-188.compute-1.amazonaws.com/openrpc-playground.html
JSON-RPC 2.0 API spec:http://ec2-18-215-163-188.compute-1.amazonaws.com/openrpc-spec.json
Проєкт зроблено з використанням фреймворків Slim Framework 4 та Doctrine. При виконанні проекта намагався дотримуватись принципів Domain Driven Design, чистої архітектури та CQRS паттерну.
- Доменна логіка розміщена в
src/Domain, у Value Objects (Email,Repo,Id) виконується валідація данних, entitySubscriptionявляє собою Rich Domain Model з інкапсульованою бізнес логікою (методиconfirm(),unsubscribe(),updateLastSeenTag()). - Використовується Repository Pattern - інтерфейс репозиторію на стороні домену, конкретна реалізація інтерфейсу - на стороні інфраструктури (
Infrastructure/DoctrineSubscriptionRepository.php). - Доменні сервіси (
src/Domain/Subscription/Service) являють собою чітковизначені інтерфейси, які реалізуються на стороні інфраструктури або конкретні сервіси які не належать до entity, але використовуються в межах бізнес логіки (в use cases). - Use cases (
src/Domain/Subscription/UseCase) являють собою сценарії використання нашої бізнес-логіки, кожен сценарій являє собою команду (Command) та обробник (Handler), вони аркеструють роботу доменних об'єктів не містячи бізнес логіки самі по собі. - В контексті CQRS паттерну use cases являють собою команди (Command) які використовують доменні сутності та змінють стан системи, a
src/Domain/ReadModel/Subscription/SubscriptionFetcherявляє собою модель запросів (Query), які для відображення інформації використовують швидкі оптимізовані запроси в базу даних (PDO). src/Infrastructure- імплементація інтерфейсів доменних об'єктів, інтеграція з зовнішніми сервісами (Mailer, GitHub) та репозіторієм.
Реалізовані unit tests та integration tests. Структура папок у тестах відповідає структурі папок доменних об'єктів.
- Unit tests працюють повністю ізольовано від зовнішнього середовища - не використовують базу данних, не відсилають повідомлення на електронну пошту, не використовують зовнішні API (GitHub), замість цього використовують mock-об'єкти. Unit тестами покрита доменна логіка та use cases.
- Інтеграційні тести перевіряють роботу контроллерів з реальними HTTP запросами, тестовою базою данних та меілером (Mailpit). (Але запроси в GitHub API імітуються). Також інтеграційними тестами перевіряється робота реальних Mailer, Repository та ReadModel.
- Також зроблений тест який тестує цілком весь флоу підписки та відписки, це мабуть вже можна віднести до E2E тестів.
Для періодичного сканування підписок реалізовано cron job який запускається раз на 5 хвилин і сканує всі активні підписки. Для локальної розробки в якості mail сервера використовується Mailpit, вебінтерфейс якого доступний за адресою http://localhost:8025.
У нас є два сценарії отримання помилок 429 Too Many Requests від зовнішнього API:
-
Під час підписки на репозиторій: Ми повертаємо користувачу наступний респонс:
{ "error": "GitHub API rate limit exceeded. Retry after 120 seconds.", "retry_after": 120 }Таким чином він знає причину помилки і знає через який час спробувати знову.
-
Під час роботи cron job зі сканування репозіторіїв: При отриманні помилки 429 - припиняємо всю подальшу роботу так як немає сенсу продовжувати далі. Через 5 хвилин процесс сканування запуститься знову і якщо rate limit збросився - повторюємо сканування.
- Користувач підписується на репозиторій.
- Йому приходить лист із посиланням на підтвердження підписки.
- Користувач підтверджує підписку на репозиторій.
- При публікації нової версії репозиторію користувач отримує лист із посиланням на нову версію. Також у листі є кнопка для відписки від репозиторію.
Деплой виконується на AWS EC2 instance через CI/CD pipeline. Деплоймент флоу виглядає наступним чином:
- Push комміта в репозіторій.
- Після push тригериться CI pipeline.
- Запускається лінтер.
- Запускаються тести.
- Якщо попередні кроки пройшли успішно - запускається CD pipeline.
- Білдиться docker image.
- Docker image пушиться в DockerHub.
- SSH to EC2 → Pull new image → Restart containers.
- Run migrations → Verify deployment.
Конфігурація Docker контейнерів для прода відрізняється від конфігурації для локального розроблення.
- 5 services: slim, postgres, redis, mailer, cron
- Uses PHP built-in server (
php -S) - Includes Mailpit (email testing tool)
- Separate cron service for scheduled tasks
- 3 services: app, postgres, redis
- Uses Nginx + PHP-FPM (via
Dockerfile.prod) - Sendgrid SMTP instead of mail testing tool
- Cron handled inside app container (via Supervisor)
- Multi-stage builds
Для реалізації Redis-кешування було використано Decorator pattern. CachedGitHubRepositoryChecker декорує GitHubRepositoryChecker, обидва реалізують інтерфейс GitHubRepositoryChecker, декоратор додає кешуючу поведінку "навколо" оригінальної поведінки, не змінюючи її кода.
Додано middleware для перевірки API ключа в X-API-KEY header. Middleware застосовано для всіх /api роутів. Довелося додати ключ до HTML сторінки та змінити swagger.yaml В swagger.yaml додано securityDefinitions секція, 401 response до всіх ендпоінтів.
Використовуються наступні метрики:
- http_requests_total:Total number of HTTP requests
- http_requests_in_progress:Number of HTTP requests currently being processed
- http_request_duration_seconds:HTTP request duration in seconds
- db_queries_total:Total number of database queries
- emails_sent_total:Total number of emails sent
Метрики доступні за адресами:
Додан gRPC-інтерфейс як доповнення до REST API. Обидва інтерфейси використовують наявну бізнес-логіку. Кожен метод реалізовано окремим обробником, який використовує наявні use cases.