import httpx from fastapi import FastAPI, HTTPException from pydantic import BaseModel from circuit_breaker import CircuitBreaker app = FastAPI() USER_SERVICE_URL = "http://user-service:8000" CATALOG_SERVICE_URL = "http://catalog-service:8000" orders_db = {} next_id = 1 catalog_cb = CircuitBreaker(failure_threshold=3, recovery_timeout=10) class CreateOrderDTO(BaseModel): user_id: int product_id: int quantity: int TIMEOUT = 5.0 def get_product(product_id: int): return catalog_cb.call( httpx.get, f"{CATALOG_SERVICE_URL}/products/{product_id}", timeout=TIMEOUT ) @app.post("/orders", status_code=201) async def create_order(payload: CreateOrderDTO): global next_id user_response = httpx.get(f"{USER_SERVICE_URL}/users/{payload.user_id}") try: user_response = httpx.get(f"{USER_SERVICE_URL}/users/{payload.user_id}", timeout=TIMEOUT) except httpx.TimeoutException: raise HTTPException(status_code=503, detail="User service unavailable") if user_response.status_code == 404: raise HTTPException(status_code=404, detail="User not found") user = user_response.json() try: product_response = get_product(payload.product_id) except httpx.TimeoutException: raise HTTPException(status_code=503, detail="Catalog service unavailable") if product_response.status_code == 404: raise HTTPException(status_code=404, detail="Product not found") product = product_response.json() try: update_response = httpx.put(f"{CATALOG_SERVICE_URL}/products/{payload.product_id}/stock", json= {"quantity": payload.quantity}, timeout=TIMEOUT) except httpx.TimeoutException: raise HTTPException(status_code=503, detail="Catalog service unavailable") if update_response.status_code == 400: raise HTTPException(status_code= 400, detail= "Stock Insuffisant") if update_response.status_code != 200: raise HTTPException(status_code= 502, detail= "Erreur catalog-service") order_id = next_id next_id += 1 new_order = { "id": order_id, "user_id": user["id"], "user_name": user["name"], "product_id": product["id"], "product_name": product["name"], "unit_price": product["price"], "quantity": payload.quantity, "total_price": product["price"] * payload.quantity } orders_db[order_id] = new_order return new_order @app.get("/orders/{order_id}") async def get_order(order_id: int): order = orders_db.get(order_id) if not order: raise HTTPException(status_code=404, detail="Order not found") return order @app.get("/health") def health(): return {"status": "ok", "service": "order-service"}