Fix docker
This commit is contained in:
@@ -15,27 +15,32 @@ class Settings(BaseSettings):
|
|||||||
DEBUG: bool = os.getenv("DEBUG", "False").lower() == "true"
|
DEBUG: bool = os.getenv("DEBUG", "False").lower() == "true"
|
||||||
LOG_LEVEL: str = os.getenv("LOG_LEVEL", "INFO")
|
LOG_LEVEL: str = os.getenv("LOG_LEVEL", "INFO")
|
||||||
|
|
||||||
# CORS settings
|
# CORS settings - FIXED: Remove List[str] type and parse manually
|
||||||
CORS_ORIGINS: List[str] = os.getenv("CORS_ORIGINS", "http://localhost:3000,http://localhost:3001").split(",")
|
CORS_ORIGINS: str = "http://localhost:3000,http://localhost:3001"
|
||||||
|
|
||||||
# Service URLs
|
# Service URLs
|
||||||
AUTH_SERVICE_URL: str = os.getenv("AUTH_SERVICE_URL", "http://auth-service:8000")
|
AUTH_SERVICE_URL: str = "http://auth-service:8000"
|
||||||
TRAINING_SERVICE_URL: str = os.getenv("TRAINING_SERVICE_URL", "http://training-service:8000")
|
TRAINING_SERVICE_URL: str = "http://training-service:8000"
|
||||||
FORECASTING_SERVICE_URL: str = os.getenv("FORECASTING_SERVICE_URL", "http://forecasting-service:8000")
|
FORECASTING_SERVICE_URL: str = "http://forecasting-service:8000"
|
||||||
DATA_SERVICE_URL: str = os.getenv("DATA_SERVICE_URL", "http://data-service:8000")
|
DATA_SERVICE_URL: str = "http://data-service:8000"
|
||||||
TENANT_SERVICE_URL: str = os.getenv("TENANT_SERVICE_URL", "http://tenant-service:8000")
|
TENANT_SERVICE_URL: str = "http://tenant-service:8000"
|
||||||
NOTIFICATION_SERVICE_URL: str = os.getenv("NOTIFICATION_SERVICE_URL", "http://notification-service:8000")
|
NOTIFICATION_SERVICE_URL: str = "http://notification-service:8000"
|
||||||
|
|
||||||
# Redis settings
|
# Redis settings
|
||||||
REDIS_URL: str = os.getenv("REDIS_URL", "redis://redis:6379/6")
|
REDIS_URL: str = "redis://redis:6379/6"
|
||||||
|
|
||||||
# Rate limiting
|
# Rate limiting
|
||||||
RATE_LIMIT_REQUESTS: int = int(os.getenv("RATE_LIMIT_REQUESTS", "100"))
|
RATE_LIMIT_REQUESTS: int = 100
|
||||||
RATE_LIMIT_WINDOW: int = int(os.getenv("RATE_LIMIT_WINDOW", "60"))
|
RATE_LIMIT_WINDOW: int = 60
|
||||||
|
|
||||||
# JWT settings
|
# JWT settings
|
||||||
JWT_SECRET_KEY: str = os.getenv("JWT_SECRET_KEY", "your-secret-key-change-in-production")
|
JWT_SECRET_KEY: str = "your-secret-key-change-in-production"
|
||||||
JWT_ALGORITHM: str = os.getenv("JWT_ALGORITHM", "HS256")
|
JWT_ALGORITHM: str = "HS256"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def CORS_ORIGINS_LIST(self) -> List[str]:
|
||||||
|
"""Parse CORS origins from string to list"""
|
||||||
|
return [origin.strip() for origin in self.CORS_ORIGINS.split(",") if origin.strip()]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def SERVICES(self) -> Dict[str, str]:
|
def SERVICES(self) -> Dict[str, str]:
|
||||||
@@ -49,4 +54,7 @@ class Settings(BaseSettings):
|
|||||||
"notification": self.NOTIFICATION_SERVICE_URL
|
"notification": self.NOTIFICATION_SERVICE_URL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
env_file = ".env"
|
||||||
|
|
||||||
settings = Settings()
|
settings = Settings()
|
||||||
@@ -40,10 +40,10 @@ metrics_collector = MetricsCollector("gateway")
|
|||||||
# Service discovery
|
# Service discovery
|
||||||
service_discovery = ServiceDiscovery()
|
service_discovery = ServiceDiscovery()
|
||||||
|
|
||||||
# CORS middleware
|
# CORS middleware - FIXED: Use the parsed list property
|
||||||
app.add_middleware(
|
app.add_middleware(
|
||||||
CORSMiddleware,
|
CORSMiddleware,
|
||||||
allow_origins=settings.CORS_ORIGINS,
|
allow_origins=settings.CORS_ORIGINS_LIST,
|
||||||
allow_credentials=True,
|
allow_credentials=True,
|
||||||
allow_methods=["*"],
|
allow_methods=["*"],
|
||||||
allow_headers=["*"],
|
allow_headers=["*"],
|
||||||
|
|||||||
66
gateway/app/routes/data.py
Normal file
66
gateway/app/routes/data.py
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
"""
|
||||||
|
Data routes for gateway
|
||||||
|
"""
|
||||||
|
|
||||||
|
from fastapi import APIRouter, Request, HTTPException
|
||||||
|
from fastapi.responses import JSONResponse
|
||||||
|
import httpx
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from app.core.config import settings
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
@router.post("/upload")
|
||||||
|
async def upload_sales_data(request: Request):
|
||||||
|
"""Proxy data upload to data service"""
|
||||||
|
try:
|
||||||
|
body = await request.body()
|
||||||
|
auth_header = request.headers.get("Authorization")
|
||||||
|
|
||||||
|
async with httpx.AsyncClient(timeout=30.0) as client:
|
||||||
|
response = await client.post(
|
||||||
|
f"{settings.DATA_SERVICE_URL}/upload",
|
||||||
|
content=body,
|
||||||
|
headers={
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": auth_header
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=response.status_code,
|
||||||
|
content=response.json()
|
||||||
|
)
|
||||||
|
|
||||||
|
except httpx.RequestError as e:
|
||||||
|
logger.error(f"Data service unavailable: {e}")
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=503,
|
||||||
|
detail="Data service unavailable"
|
||||||
|
)
|
||||||
|
|
||||||
|
@router.get("/sales")
|
||||||
|
async def get_sales_data(request: Request):
|
||||||
|
"""Get sales data"""
|
||||||
|
try:
|
||||||
|
auth_header = request.headers.get("Authorization")
|
||||||
|
|
||||||
|
async with httpx.AsyncClient(timeout=10.0) as client:
|
||||||
|
response = await client.get(
|
||||||
|
f"{settings.DATA_SERVICE_URL}/sales",
|
||||||
|
headers={"Authorization": auth_header}
|
||||||
|
)
|
||||||
|
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=response.status_code,
|
||||||
|
content=response.json()
|
||||||
|
)
|
||||||
|
|
||||||
|
except httpx.RequestError as e:
|
||||||
|
logger.error(f"Data service unavailable: {e}")
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=503,
|
||||||
|
detail="Data service unavailable"
|
||||||
|
)
|
||||||
66
gateway/app/routes/forecasting.py
Normal file
66
gateway/app/routes/forecasting.py
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
"""
|
||||||
|
Forecasting routes for gateway
|
||||||
|
"""
|
||||||
|
|
||||||
|
from fastapi import APIRouter, Request, HTTPException
|
||||||
|
from fastapi.responses import JSONResponse
|
||||||
|
import httpx
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from app.core.config import settings
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
@router.post("/predict")
|
||||||
|
async def create_forecast(request: Request):
|
||||||
|
"""Proxy forecast request to forecasting service"""
|
||||||
|
try:
|
||||||
|
body = await request.body()
|
||||||
|
auth_header = request.headers.get("Authorization")
|
||||||
|
|
||||||
|
async with httpx.AsyncClient(timeout=30.0) as client:
|
||||||
|
response = await client.post(
|
||||||
|
f"{settings.FORECASTING_SERVICE_URL}/predict",
|
||||||
|
content=body,
|
||||||
|
headers={
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": auth_header
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=response.status_code,
|
||||||
|
content=response.json()
|
||||||
|
)
|
||||||
|
|
||||||
|
except httpx.RequestError as e:
|
||||||
|
logger.error(f"Forecasting service unavailable: {e}")
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=503,
|
||||||
|
detail="Forecasting service unavailable"
|
||||||
|
)
|
||||||
|
|
||||||
|
@router.get("/forecasts")
|
||||||
|
async def get_forecasts(request: Request):
|
||||||
|
"""Get forecasts"""
|
||||||
|
try:
|
||||||
|
auth_header = request.headers.get("Authorization")
|
||||||
|
|
||||||
|
async with httpx.AsyncClient(timeout=10.0) as client:
|
||||||
|
response = await client.get(
|
||||||
|
f"{settings.FORECASTING_SERVICE_URL}/forecasts",
|
||||||
|
headers={"Authorization": auth_header}
|
||||||
|
)
|
||||||
|
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=response.status_code,
|
||||||
|
content=response.json()
|
||||||
|
)
|
||||||
|
|
||||||
|
except httpx.RequestError as e:
|
||||||
|
logger.error(f"Forecasting service unavailable: {e}")
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=503,
|
||||||
|
detail="Forecasting service unavailable"
|
||||||
|
)
|
||||||
66
gateway/app/routes/notification.py
Normal file
66
gateway/app/routes/notification.py
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
"""
|
||||||
|
Notification routes for gateway
|
||||||
|
"""
|
||||||
|
|
||||||
|
from fastapi import APIRouter, Request, HTTPException
|
||||||
|
from fastapi.responses import JSONResponse
|
||||||
|
import httpx
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from app.core.config import settings
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
@router.post("/send")
|
||||||
|
async def send_notification(request: Request):
|
||||||
|
"""Proxy notification request to notification service"""
|
||||||
|
try:
|
||||||
|
body = await request.body()
|
||||||
|
auth_header = request.headers.get("Authorization")
|
||||||
|
|
||||||
|
async with httpx.AsyncClient(timeout=10.0) as client:
|
||||||
|
response = await client.post(
|
||||||
|
f"{settings.NOTIFICATION_SERVICE_URL}/send",
|
||||||
|
content=body,
|
||||||
|
headers={
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": auth_header
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=response.status_code,
|
||||||
|
content=response.json()
|
||||||
|
)
|
||||||
|
|
||||||
|
except httpx.RequestError as e:
|
||||||
|
logger.error(f"Notification service unavailable: {e}")
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=503,
|
||||||
|
detail="Notification service unavailable"
|
||||||
|
)
|
||||||
|
|
||||||
|
@router.get("/history")
|
||||||
|
async def get_notification_history(request: Request):
|
||||||
|
"""Get notification history"""
|
||||||
|
try:
|
||||||
|
auth_header = request.headers.get("Authorization")
|
||||||
|
|
||||||
|
async with httpx.AsyncClient(timeout=10.0) as client:
|
||||||
|
response = await client.get(
|
||||||
|
f"{settings.NOTIFICATION_SERVICE_URL}/history",
|
||||||
|
headers={"Authorization": auth_header}
|
||||||
|
)
|
||||||
|
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=response.status_code,
|
||||||
|
content=response.json()
|
||||||
|
)
|
||||||
|
|
||||||
|
except httpx.RequestError as e:
|
||||||
|
logger.error(f"Notification service unavailable: {e}")
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=503,
|
||||||
|
detail="Notification service unavailable"
|
||||||
|
)
|
||||||
66
gateway/app/routes/tenant.py
Normal file
66
gateway/app/routes/tenant.py
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
"""
|
||||||
|
Tenant routes for gateway
|
||||||
|
"""
|
||||||
|
|
||||||
|
from fastapi import APIRouter, Request, HTTPException
|
||||||
|
from fastapi.responses import JSONResponse
|
||||||
|
import httpx
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from app.core.config import settings
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
@router.post("/")
|
||||||
|
async def create_tenant(request: Request):
|
||||||
|
"""Proxy tenant creation to tenant service"""
|
||||||
|
try:
|
||||||
|
body = await request.body()
|
||||||
|
auth_header = request.headers.get("Authorization")
|
||||||
|
|
||||||
|
async with httpx.AsyncClient(timeout=10.0) as client:
|
||||||
|
response = await client.post(
|
||||||
|
f"{settings.TENANT_SERVICE_URL}/tenants",
|
||||||
|
content=body,
|
||||||
|
headers={
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": auth_header
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=response.status_code,
|
||||||
|
content=response.json()
|
||||||
|
)
|
||||||
|
|
||||||
|
except httpx.RequestError as e:
|
||||||
|
logger.error(f"Tenant service unavailable: {e}")
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=503,
|
||||||
|
detail="Tenant service unavailable"
|
||||||
|
)
|
||||||
|
|
||||||
|
@router.get("/")
|
||||||
|
async def get_tenants(request: Request):
|
||||||
|
"""Get tenants"""
|
||||||
|
try:
|
||||||
|
auth_header = request.headers.get("Authorization")
|
||||||
|
|
||||||
|
async with httpx.AsyncClient(timeout=10.0) as client:
|
||||||
|
response = await client.get(
|
||||||
|
f"{settings.TENANT_SERVICE_URL}/tenants",
|
||||||
|
headers={"Authorization": auth_header}
|
||||||
|
)
|
||||||
|
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=response.status_code,
|
||||||
|
content=response.json()
|
||||||
|
)
|
||||||
|
|
||||||
|
except httpx.RequestError as e:
|
||||||
|
logger.error(f"Tenant service unavailable: {e}")
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=503,
|
||||||
|
detail="Tenant service unavailable"
|
||||||
|
)
|
||||||
@@ -11,3 +11,4 @@ python-json-logger==2.0.4
|
|||||||
email-validator==2.0.0
|
email-validator==2.0.0
|
||||||
aio-pika==9.3.0
|
aio-pika==9.3.0
|
||||||
pytz==2023.3
|
pytz==2023.3
|
||||||
|
python-logstash==0.4.8
|
||||||
@@ -4,3 +4,6 @@ Messaging service for training service
|
|||||||
|
|
||||||
from shared.messaging.rabbitmq import RabbitMQClient
|
from shared.messaging.rabbitmq import RabbitMQClient
|
||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
|
|
||||||
|
# Global message publisher
|
||||||
|
message_publisher = RabbitMQClient(settings.RABBITMQ_URL)
|
||||||
Reference in New Issue
Block a user