I succesfully deployed my FastAPI app to azure, but when I try to access the routes, it says 404 not found. However, when I test the same route locally it works. My db is hosted on azure. I tried adding a startup.sh file with this command: gunicorn -w 4 -k uvicorn.workers.UvicornWorker main:app, without any luck. Thhis is my database.py: import pyodbc import logging import sys # Set up logging to output to stdout (which Azure captures) logging.basicConfig(level=logging.INFO, stream=sys.stdout, format='%(asctime)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) def get_db_connection(): server = '//' # Azure SQL server name database = '//' # Database name username = '//' # Username password = '//' # Password driver = '{ODBC Driver 18 for SQL Server}' # Driver for SQL Server # Create a connection string connection_string = f'DRIVER={driver};SERVER={server};PORT=1433;DATABASE={database};UID={username};PWD={password}' try: # Log the attempt to connect logger.info("Attempting to connect to the database...") # Establish the connection conn = pyodbc.connect(connection_string) # Log success logger.info("Successfully connected to the database.") return conn except Exception as e: # Log any connection error logger.error(f"Failed to connect to the database: {e}") raise My main.py: from fastapi import FastAPI, Query, HTTPException import pyodbc from database import get_db_connection import traceback import logging # Set up logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) app = FastAPI() def get_user_organizational_unit_code() -> str: # This is the hardcoded default organizational unit code return "0000-0010" @app.get("/chargers") async def get_chargers(organizationalUnitCode: str = Query(..., description="The organizational unit code to filter chargers")): """ Fetch chargers based on the provided organizational unit code. """ try: if not organizationalUnitCode: raise HTTPException(status_code=400, detail="No organizationalUnitCode provided.") # Log the received organizational unit code logger.info(f"Received organizationalUnitCode: {organizationalUnitCode}") # Establish the connection to the database conn = get_db_connection() cursor = conn.cursor() # Log the query being executed logger.info(f"Executing query for organizationalUnitCode: {organizationalUnitCode}") # Query chargers based on the organizational unit code cursor.execute(""" SELECT * FROM [dbo].[chargepointStatus] WHERE organizationalUnitCode = ? """, organizationalUnitCode) # Fetch all rows from the query result rows = cursor.fetchall() # Log the number of results found logger.info(f"Query returned {len(rows)} results for organizationalUnitCode: {organizationalUnitCode}") # If no rows are returned, raise a 404 exception if not rows: logger.warning(f"No chargers found for the provided organizational unit code: {organizationalUnitCode}") return {"detail": "No chargers found for the provided organizational unit code."} # Format the result chargers = [{ "ID": row[0], "chargepointID": row[1], "name": row[2], "connector": row[3], "location": row[4], "status": row[5], "statusError": row[6], "statusTime": row[7], "networkStatus": row[8], "networkStatusTime": row[9], "mailContactOffline": row[10], "mailContactStatus": row[11], "mailContactOfflineLate": row[12], "organizationalUnitCode": row[13], "organizationalUnitName": row[14], } for row in rows] # Log the result logger.info(f"Returning {len(chargers)} chargers for organizationalUnitCode: {organizationalUnitCode}") # Close the cursor and the connection cursor.close() conn.close() return {"chargers": chargers} except HTTPException as http_err: # Log HTTP-specific errors logger.error(f"HTTP error occurred: {http_err.detail}") return {"detail": http_err.detail} except Exception as e: # Log the exception for debugging logger.error(f"Error: {e}") logger.error(traceback.format_exc()) return {"detail": "Internal Server Error", "error": str(e)} My yaml file for deployment: name: Build and deploy Python app to Azure Web App - watkanikladenapi on: push: branches: - main workflow_dispatch: jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python version uses: actions/setup-python@v5 with: python-version: '3.10' - name: Clear pip cache run: pip cache purge - name: Install system dependencies for pyodbc run: sudo apt-get install -y unixodbc-dev g++ python3-dev - name: Create and start virtual environment run: | python -m venv venv source venv/bin/activate - name: Install dependencies run: pip install -r requirements.txt # Optional: Add step to run tests here (PyTest, Django test suites, etc.) - name: Zip artifact for deployment run: zip release.zip ./* -r - name: Upload artifact for deployment jobs uses: actions/upload-artifact@v4 with: name: python-app path: | release.zip !venv/ deploy: runs-on: ubuntu-latest needs: build environment: name: 'Production' url: ${{ steps.deploy-to-webapp.outputs.webapp-url }} permissions: id-token: write # This is required for requesting the JWT steps: - name: Download artifact from build job uses: actions/download-artifact@v4 with: name: python-app - name: Unzip artifact for deployment run: unzip release.zip - name: Login to Azure uses: azure/login@v2 with: client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID= }} tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID }} subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID}} - name: 'Deploy to Azure Web App' uses: azure/webapps-deploy@v3 id: deploy-to-webapp with: app-name: 'watkanikladenapi' slot-name: 'Productio ' and my requirements.txt: fastapi==0.95.0 uvicorn==0.20.0 pyodbc==4.0.34 --find-links https://github.com/mkleehammer/pyodbc/releases gunicorn==20.0.4 Continue reading...