Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Readme file updated along with other validations #42

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
SECRET_KEY=your_secret_key
# Database Configuration
DB_NAME=
DB_HOSTNAME=localhost
DB_PORT=3306
DB_USERNAME=
DB_PASSWORD=
DB_HOSTNAME=
DB_PORT=
DB_NAME=
SECRET_KEY=
REDIS_URL=
DB_ROOT_PASSWORD=
# Additional Configuration
REDIS_URL=redis://localhost:6379/
SENTRY_DSN=
SLACK_WEBHOOK_URL=
ENVIRONMENT_NAME=
DB_ROOT_PASSWORD= //this is applicable for .env.local file only
// you will get these data from signoz portal
# Advance Usage - Signoz Configuration
OTEL_RESOURCE_ATTRIBUTES=
OTEL_EXPORTER_OTLP_ENDPOINT=
OTEL_EXPORTER_OTLP_HEADERS=
OTEL_EXPORTER_OTLP_PROTOCOL=
CACHE_ENABLED=
SENTRY_ENABLED=
SLACK_ENABLED=
# Docker Configuration
ENVIRONMENT_NAME=
133 changes: 90 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,20 @@ This repository provides a template for creating and deploying a FastAPI project

- [Features](#features)
- [Getting started](#getting-started)
- [Initialize & Setup Environment](#1-initialize--setup-environment)
- [Variables Configuration](#2-variables-configuration)
- [Database Migrations](#3-database-migrations)
- [Redis Dependency & Installation](#4-redis-dependency)
- [Celery Dependency](#5-celery-dependency)
- [Run the Project](#6-run-the-project)
- [Advanced Usage](#advanced-usage)
- [Circuit breakers](#circuit-breakers)
- [Configuring Signoz Monitoring Tool](#configuring-signoz-monitoring-tool)
- [Logging with Signoz](#logging-with-signoz)
- [Database Monitoring Using Percona](#database-monitoring-using-percona)
- [Deploy Service on AWS ECS](#deploy-service-on-aws-ecs)
- [Related Dashboard Links](#related-dashboard-links)
- [Additional Useful scripts](#additional-useful-scripts)

### Features

Expand Down Expand Up @@ -38,23 +51,42 @@ This repository provides a template for creating and deploying a FastAPI project
- Docker
- mysql

#### 1. Initialize Local Environment
#### 1. Initialize & Setup Environment

- To set up your local environment, run the following script:
- To initialize and set up your environment, run the following script:

```
./scripts/initialize-env.sh
```

This script installs the necessary dependencies and prepares the environment for running the FastAPI application on your local machine.
This script installs the necessary dependencies and prepares the environment for running the FastAPI application on your machine.

Create a .env.local file with reference of .env.example
Run following command to inject env file
```shell
set -a source .env.local set +a
```
##### Activate the environment
```
# Mac & Linux:
source ./venv/bin/activate

# Windows
.\venv\scripts\activate
```

#### 2. Variables Configuration
Update database environment variables in your .env.local file:
```
DB_NAME=
DB_HOSTNAME=localhost
DB_PORT=3306
DB_USERNAME=
DB_PASSWORD=
```
Additional Configuration (Optional):
```
SENTRY_DSN=
SLACK_WEBHOOK_URL=
DB_ROOT_PASSWORD=
```

#### 2. Database Migrations
#### 3. Database Migrations
Create new database migrations when you make changes to your models. Use the following command:
```
alembic revision -m 'brief description of changes'
Expand All @@ -68,24 +100,40 @@ alembic upgrade head
```
This command updates the database schema to reflect the latest changes defined in the migration scripts

#### 3. Redis Dependency
#### 4. Redis Dependency
##### Install Locally:
```
docker run --name recorder-redis -p 6379:6379 -d redis:alpine
# Mac
brew install redis
brew services start redis

# Windows
Please refer: https://developer.redis.com/create/windows/

# Linux
sudo apt install redis
sudo systemctl enable redis
sudo systemctl start redis
sudo systemctl status redis # verify status

```
or add the REDIS_URL in .env.local file

##### Install via docker:
```
docker run --name recorder-redis -p 6379:6379 -d redis:alpine
```

#### 4. Celery Dependency
- Run following command to initiallize the celery worker
```shell
celery -A app.app.celery worker -l info
```
- Turn Up Celery Flower with
```shell
flower --broker=${REDIS_URL}/6 --port=5555
```
#### 5. Celery Dependency
Run following command to initiallize the celery worker
```
celery -A app.app.celery worker -l info
```
[Optional] Turn Up Celery Flower with
```
flower --broker=${REDIS_URL}/6 --port=5555
```

#### 5. Run the Project
#### 6. Run the Project

##### Running Application Locally

Expand All @@ -106,23 +154,9 @@ This script upgrades the database migrations using Alembic and starts the FastAP
docker compose --env-file .env.docker up
```

### Advanced Usage

#### 6. Deploy Service on AWS ECS
To deploy the FastAPI application on AWS ECS, use the following script:

```
./scripts/setup-ecs.sh develop
```

The setup-ecs.sh script leverages AWS Copilot to deploy the service. Provide the environment name as an argument (e.g., develop). The script creates and deploys an environment, then deploys the FastAPI service on that environment.

Note: Ensure you have AWS credentials configured and AWS Copilot installed for successful deployment.

#### New to AWS Copilot?
If you are new to AWS Copilot or you want to learn more about AWS Copilot, please refer to [this helpful article](https://www.wednesday.is/writing-tutorials/how-to-use-copilot-to-deploy-projects-on-ecs) that guides you through the process of setting up AWS Copilot locally as well as also helps you understand how you can publish and update an application using 4 simple steps.


#### 7. Circuit breakers
#### Circuit breakers

Using the Circuit Breaker for External API Calls

Expand All @@ -147,9 +181,7 @@ async def external_service_endpoint():
raise HTTPException(status_code=503, detail="Service temporarily unavailable")
```

### Advanced Usage

#### Using Signoz Monitoring Tool
#### Configuring Signoz Monitoring Tool

To utilize Signoz for monitoring your applications, follow these steps:

Expand Down Expand Up @@ -236,14 +268,29 @@ To monitor your database using Percona, follow these steps:

By following these steps, you'll successfully configure Percona to monitor your MySQL database.

#### Dashboard Links
#### Deploy Service on AWS ECS
To deploy the FastAPI application on AWS ECS, use the following script:

```
./scripts/setup-ecs.sh develop
```

The setup-ecs.sh script leverages AWS Copilot to deploy the service. Provide the environment name as an argument (e.g., develop). The script creates and deploys an environment, then deploys the FastAPI service on that environment.

Note: Ensure you have AWS credentials configured and AWS Copilot installed for successful deployment.

#### New to AWS Copilot?
If you are new to AWS Copilot or you want to learn more about AWS Copilot, please refer to [this helpful article](https://www.wednesday.is/writing-tutorials/how-to-use-copilot-to-deploy-projects-on-ecs) that guides you through the process of setting up AWS Copilot locally as well as also helps you understand how you can publish and update an application using 4 simple steps.


#### Related Dashboard Links
- Percona: https://localhost:443
- Flower: http://localhost:5556
- Locust UI: http://localhost:8089
- Swagger UI: http://localhost:8000


#### Useful scripts
#### Additional Useful scripts
- Tests - scripts/run_tests.sh
- Linting & Formatting - scripts/lint_and_format.sh
- Load tests - scripts/load_tests.sh (Change [locust.conf](https://docs.locust.io/en/stable/configuration.html) accordinly)
7 changes: 5 additions & 2 deletions app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,15 @@


# Sentry Initialization
if settings.SENTRY_ENABLED:
if settings.SENTRY_DSN:
sentry_sdk.init(
dsn=settings.SENTRY_DSN,
traces_sample_rate=1.0, # Sample rate of 100%
)

# Check required environment variables
settings.check_environment_variables()

app = FastAPI(
title="FastAPI Template",
description="This is my first API use FastAPI",
Expand All @@ -49,7 +52,7 @@
app.add_middleware(RequestIdInjection)
app.add_middleware(CacheMiddleware, cached_endpoints=cached_endpoints.CACHED_ENDPOINTS)

if settings.SENTRY_ENABLED:
if settings.SENTRY_DSN:
try:
app.add_middleware(SentryAsgiMiddleware)
except Exception as e:
Expand Down
27 changes: 14 additions & 13 deletions app/config/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,29 @@ class DBSettings(BaseSettings):
DB_PASSWORD: str

class Config:
env_file = ".env"
env_file = ".env.local"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how will it behave with .env.docker file Add a comment here please

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, I researched a bit and found out that each env file is unique.
And so by the previous '.env', your docker wouldn't work cause if you'll check your compose file it is .env.${environment_name} now in any case it will never be .env and docker won't work and so I've standardized it and fixed your docker error too.

Here's you can repro the uniqueness,
change your .env file to .env.local in your current code and run it.

Also there is a hierarchy of it:
Here's the priority of the files for the development build and the production build:
Dev.: (npm start): .env.development.local, .env.local, .env.development, .env
Prod.: (npm run build): .env.production.local, .env.local, .env.production, .env

And so by this .env.local is pretty standard and solves your compose problem too

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dont harcode. .env.local keep it .env.${environment_name} i mean to say this

Copy link
Collaborator Author

@anasnadeemws anasnadeemws Apr 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, for it take the environment name it has to go to .env file and for it to go to environment file it has to know the .env file.

It's not gonna work as it's a circular thing. We can have some sort of hack here tho but that's not gonna remain a standard base file

Also please go through the hierarchy pattern I've mentioned.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reference link please

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.



class FlagFeatureSettings(BaseSettings):
CACHE_ENABLED: bool
SENTRY_ENABLED: bool = False
SLACK_ENABLED: bool = False

class Config:
env_file = ".env"


class Settings(FlagFeatureSettings, DBSettings):
class Settings(DBSettings):
SECRET_KEY: str
REDIS_URL: str
SENTRY_DSN: str | None
SLACK_WEBHOOK_URL: str
SLACK_WEBHOOK_URL: str | None
ALLOWED_HOSTS: list = ["*"]
CACHE_MAX_AGE: int = 60

class Config:
env_file = ".env"
env_file = ".env.local"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above


def check_environment_variables(self):
if not self.DB_HOSTNAME or not self.DB_PORT or not self.DB_NAME or not self.DB_USERNAME or not self.DB_PASSWORD:
raise ValueError("Database environment variables are not set")

if not self.SECRET_KEY:
raise ValueError("SECRET_KEY is not set")

if not self.REDIS_URL:
raise ValueError("REDIS_URL is not set")


class CachedEndpoints(BaseSettings):
Expand Down
2 changes: 1 addition & 1 deletion app/routes/home/home.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ async def external_service_endpoint():

@home_router.get("/sentry-test", tags=["Home"])
def sentry_endpoint():
if not settings.SENTRY_ENABLED:
if not settings.SENTRY_DSN:
raise HTTPException(status_code=503, detail="Sentry is not enabled")
raise CentryTestException("Sentry Test")

Expand Down
2 changes: 1 addition & 1 deletion app/utils/slack_notification_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def send_slack_message(payload):
Returns:
HTTP response code, i.e., <Response [503]>
"""
if not settings.SLACK_ENABLEDs:
if not settings.SLACK_WEBHOOK_URL:
return

webhook_url = settings.SLACK_WEBHOOK_URL
Expand Down
28 changes: 10 additions & 18 deletions app/wrappers/cache_wrappers.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,24 @@
from __future__ import annotations

from app.config.base import settings
from app.config.redis_config import get_redis_pool


class CacheUtils:
CACHE_ENABLED = settings.CACHE_ENABLED

@classmethod
async def create_cache(cls, resp, key: str, ex: int = 60):
if cls.CACHE_ENABLED:
redis = await get_redis_pool()
await redis.set(key, resp, ex=ex)
redis = await get_redis_pool()
await redis.set(key, resp, ex=ex)

@classmethod
async def retrieve_cache(cls, key: str):
if cls.CACHE_ENABLED:
redis = await get_redis_pool()
data = await redis.get(key)
if not data:
return None, None
expire = await redis.ttl(key)
return data, expire
return None, None
redis = await get_redis_pool()
data = await redis.get(key)
if not data:
return None, None
expire = await redis.ttl(key)
return data, expire

@classmethod
async def invalidate_cache(cls, key: str):
if cls.CACHE_ENABLED:
redis = await get_redis_pool()
await redis.delete(key)
return None
redis = await get_redis_pool()
await redis.delete(key)
2 changes: 1 addition & 1 deletion compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ services:
dockerfile: Dockerfile
command: ['celery', '-A', 'app.app.celery', 'worker', '-l', 'info']
env_file:
- .env.${ENVIRONMENT_NAME}
- .env.${ENVIRONMENT_NAME}
depends_on:
- redis
- app
Expand Down
Loading
Loading