sdcasas.dev

Troubleshooting real: errores comunes en Azure App Service con Python

Los problemas más frecuentes que vas a encontrar corriendo Python en Azure App Service y cómo resolverlos.

4 min read

Contexto

Azure App Service en Linux con Python es cómodo hasta que algo falla. Y cuando falla, los mensajes de error suelen ser crípticos o directamente vacíos.

Este post es un índice de los problemas reales que me encontré, con sus causas y soluciones.


1. La app arranca pero devuelve 503 inmediatamente

Síntoma: Deploy exitoso, pero la app responde 503 desde el primer request.

Causa más común: El startup command está mal configurado o Gunicorn no puede importar el módulo.

Diagnóstico:

# Ver los logs del contenedor en tiempo real
az webapp log tail --name my-app --resource-group my-rg

Buscá líneas como:

ModuleNotFoundError: No module named 'app.main'

Solución: Verificar el startup command en Configuration > General settings:

# Formato correcto para FastAPI con Gunicorn + Uvicorn
gunicorn -w 4 -k uvicorn.workers.UvicornWorker app.main:app

El path app.main:app asume que tenés app/main.py con una variable app = FastAPI().


2. Variables de entorno que no se ven desde la app

Síntoma: os.environ["MY_VAR"] lanza KeyError aunque la variable está en Application Settings.

Causa: Hiciste el cambio en el portal pero no guardaste (el botón Save no es automático) o el App Service no se reinició.

Verificación rápida:

# Endpoint de diagnóstico (solo en DEV, nunca en producción)
import os
from fastapi import APIRouter

router = APIRouter()

@router.get("/debug/env")
async def check_env():
    return {
        "MY_VAR": os.environ.get("MY_VAR", "NOT_SET"),
        "WEBSITE_SITE_NAME": os.environ.get("WEBSITE_SITE_NAME", "NOT_SET"),
    }

Si WEBSITE_SITE_NAME no aparece, el problema es más profundo.


3. Timeout en requests sin logs de error

Síntoma: Requests largos devuelven 504 sin ningún error visible en la app.

Causa: Azure App Service tiene un timeout de idle de 230 segundos por defecto que no se puede cambiar en el tier básico.

Soluciones:

  1. Mover trabajo largo a background tasks:
from fastapi import BackgroundTasks

@router.post("/process")
async def process_data(
    data: ProcessRequest,
    background_tasks: BackgroundTasks,
):
    background_tasks.add_task(run_heavy_processing, data)
    return {"status": "queued"}
  1. Usar Azure Service Bus para jobs asincrónicos:
from azure.servicebus import ServiceBusClient, ServiceBusMessage

def enqueue_job(job_data: dict) -> str:
    with ServiceBusClient.from_connection_string(SB_CONN_STR) as client:
        with client.get_queue_sender("processing-queue") as sender:
            msg = ServiceBusMessage(json.dumps(job_data))
            sender.send_messages(msg)
    return "queued"

4. Paquetes que fallan al instalar (wheels)

Síntoma: El deploy falla con:

error: legacy-install-failure
Failed building wheel for <package>

Causa: Algunos paquetes necesitan compilar extensiones en C y no tienen wheel para la plataforma del App Service (Linux/amd64, Python 3.x).

Solución:

Verificar que el requirements.txt usa la versión correcta y que el runtime de Python en App Service coincide con tu entorno de desarrollo:

# Ver el runtime configurado
az webapp config show --name my-app --resource-group my-rg --query "linuxFxVersion"
# Output esperado: "PYTHON|3.11"

Si el problema persiste, usar Docker con un Dockerfile propio:

FROM python:3.11-slim

WORKDIR /app

# Install build tools for packages with C extensions
RUN apt-get update && apt-get install -y gcc libpq-dev && rm -rf /var/lib/apt/lists/*

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD ["gunicorn", "-w", "4", "-k", "uvicorn.workers.UvicornWorker", "app.main:app", "--bind", "0.0.0.0:8000"]

5. Logs que desaparecen

Síntoma: Ves logs en az webapp log tail pero no en Log Analytics.

Causa: El envío de logs de App Service a Log Analytics Workspace requiere configuración de Diagnostic Settings que no está habilitada por defecto.

Solución en Bicep:

resource diagnostics 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = {
  name: 'app-diagnostics'
  scope: appService
  properties: {
    workspaceId: logAnalyticsWorkspace.id
    logs: [
      {
        category: 'AppServiceHTTPLogs'
        enabled: true
      }
      {
        category: 'AppServiceConsoleLogs'
        enabled: true
      }
    ]
  }
}

Checklist de diagnóstico rápido

Cuando algo falla en App Service, seguí este orden:

  1. az webapp log tail — ver el error real
  2. Check Application Settings → están guardados y el app se reinició?
  3. Check el startup command — path del módulo correcto?
  4. Health check endpoint funciona? /health devuelve 200?
  5. Managed Identity tiene los roles necesarios?
  6. El App Service Plan tiene recursos suficientes (CPU/memoria)?

Con estos pasos resolvés el 90% de los problemas comunes.