Inicio / Artículos / Desarrollo local de Azure Functions: Solución de los puntos de fallo más comunes

Desarrollo local de Azure Functions: Solución de los puntos de fallo más comunes

Aprenda cómo deben alinearse las Herramientas Básicas, los entornos de ejecución del lenguaje y Azurite, y obtenga soluciones prácticas para local.settings.json, los desencadenantes y los errores de depuración.

1892 palabras

Deje de luchar con emuladores, atajos defectuosos y errores enigmáticos: aquí está lo que realmente funciona

Si alguna vez una simple orden func start le ha mostrado una pantalla llena de texto rojo sin previo aviso, no es el único. Azure Functions funciona maravillosamente una vez que se despliega en la nube, pero hacer que funcione sin problemas en su propio portátil es lo que hace que muchos desarrolladores pierdan toda una tarde sin darse cuenta.

Esta guía omite la versión publicitaria pulida de “desarrollo local” y, en su lugar, analiza qué es lo que realmente sale mal, las razones detrás de ello y soluciones prácticas, basadas en los problemas que los desarrolladores enfrentan con frecuencia.

1. Por qué el desarrollo local de Azure Functions parece más difícil de lo que debería ser

Ejecutar Azure Functions en tu propia máquina no consiste simplemente en ejecutar algún código. En efecto, estás recreando localmente todo un entorno de ejecución en la nube: el host de Functions, las vinculaciones de desencadenamiento, las colas de almacenamiento y, ocasionalmente, la autenticación, todo ello sin tener que interactuar nunca con Azure en sí. Para que esto funcione correctamente en cada paso, se requieren tres componentes separados que estén alineados:

  • Core Tools CLI de Microsoft, que actúa como sustituto del entorno de ejecución de Functions alojado que normalmente obtendrías de Azure
  • Cualquiera que sea el lenguaje de programación y SDK en el que estén escritas tus funciones, ya sea Node.js, Python, .NET, Java o PowerShell
  • Azurite, un pequeño emulador que imita Azure Storage para que las colas, los blobs y las tablas funcionen sin necesidad de una cuenta en la nube real

Si alguna de estas tres opciones es la versión incorrecta, está mal configurada o simplemente no está activada, te encontrarás con los problemas habituales: funciones que se niegan a funcionar, mensajes de “cuenta de almacenamiento no encontrada” o un servidor que se apaga en silencio. Una vez que comprendas cómo dependen entre sí estos tres elementos, gran parte de la frustración desaparecerá.

2. Qué realmente necesitas tener instalado

Antes de tocar cualquier código de función, asegúrate de tener lo siguiente listo:

  • Azure Functions Core Tools, la herramienta de línea de comandos que ejecuta el servidor de Functions en tu ordenador
npm install -g azure-functions-core-tools@4 --unsafe-perm true
  • Un entorno de ejecución del lenguaje compatible con tu versión de Azure objetivo (por ejemplo, Node.js 18/20, Python 3.9–3.11 o .NET 8)
  • Azurite, el emulador que simula Azure Storage localmente
npm install -g azurite
  • VS Code junto con la extensión Azure Functions — no es obligatorio, pero hace que la depuración y la estructuración del proyecto sean mucho menos complicadas

Una verificación rápida que vale la pena realizar antes de seguir adelante:

func --version
node --version    # or python --version / dotnet --version

Una diferencia de versión entre Core Tools y el entorno de ejecución del lenguaje es una de las causas más sutiles y frecuentes por las que algo funciona bien en una máquina y falla en otra.

3. Configuración de tu primera aplicación funcional local

Utiliza la CLI para crear un proyecto completamente nuevo:

func init MyFunctionApp --worker-runtime node
cd MyFunctionApp
func new --name HttpTriggerExample --template "HTTP trigger"

Al ejecutarlo, se obtiene una estructura de carpetas que incluye un host.json, un local.settings.json y un directorio que contiene el código de su desencadenador. host.json gestiona las configuraciones a nivel del host, como el comportamiento de registro, los paquetes de extensiones y los tiempos de espera. local.settings.json es el archivo destinado únicamente a su equipo, y genera tanta confusión en la primera ejecución que merece una explicación específica.

4. El archivo local.settings.json — Qué hace y por qué confunde a la gente

Este archivo almacena las variables de entorno y cadenas de conexión locales. Nunca se envía a Azure; su propósito completo es la configuración exclusiva para el equipo local.

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "node"
  }
}

Dos errores recurrentes explican la mayoría de las quejas de “el host ni siquiera arranca”:

  1. Olvidar configurar AzureWebJobsStorage. Casi todas las categorías de desencadenantes — Timer, Queue, Blob — dependen de una conexión de almacenamiento, incluso durante las ejecuciones locales. Al utilizar UseDevelopmentStorage=true, el host se dirige a Azurite en lugar de a una cuenta real de Azure Storage.
  2. Configurar incorrectamente FUNCTIONS_WORKER_RUNTIME. Cuando no coincide con el lenguaje en el que realmente se está trabajando (node, python, dotnet, java, powershell), el host simplemente no cargará las funciones, mostrando generalmente un error vago en lugar de indicar claramente que el entorno de ejecución no es compatible.

5. Azurite: Su emulador de almacenamiento local (y por qué no puede prescindir de él)

Azurite sustituye a Azure Storage para cualquier aplicación que se ejecute localmente, emulando colas, bloques de datos y tablas directamente en su máquina. Omitir este paso es la causa principal de los errores StorageException o de conexiones rechazadas en cuanto se utiliza un disparador de cola o bloque de datos.

Ejecútelo en una ventana de terminal dedicada antes de abrir su aplicación funcional:

azurite --silent --location ./azurite-data --debug ./azurite-data/debug.log

Si prefiere trabajar desde VS Code, la extensión Azurite le permite iniciar el emulador mediante una sola opción en la paleta de comandos, sin necesidad de utilizar una terminal separada. Sea cual sea la opción que elija, manténgalo en ejecución durante toda su sesión; es muy fácil olvidar que no está activo y perder diez minutos intentando solucionar un mensaje de “conexión fallida” que en realidad solo indica que el emulador nunca se inició.

6. Ejecución y pruebas de funciones activadas por HTTP

Una vez que Azurite esté listo, inicie su aplicación funcional:

func start

Su terminal mostrará la URL local de cada función, algo similar a esto:

Http Functions:
    HttpTriggerExample: [GET,POST] http://localhost:7071/api/HttpTriggerExample

Puede acceder a ella con curl, Postman o un navegador si se trata de una solicitud GET:

curl "http://localhost:7071/api/HttpTriggerExample?name=Dev"

Si recibe silencio en lugar de una respuesta, busque una colisión de puertos: un proceso func start restante o otra instancia podría estar ocupando ya el puerto 7071. Finalizar los procesos host de Functions no deseados (busque func en el Administrador de tareas, o ejecute pkill -f func en macOS/Linux) generalmente resuelve el problema de inmediato.

7. Prueba de desencadenadores no HTTP localmente (Timer, Queue, Blob, Service Bus)

Los desencadenadores HTTP son el caso más sencillo. El resto requiere un poco más de preparación:

  • Desencadenantes de temporizador se activan automáticamente según su programación CRON en cuanto se inicia el host, sin necesidad de nada adicional. Para probarlos antes, puede agregar temporalmente "RunOnStartup": true a la definición del desencadenante para que se ejecute de inmediato.
  • Desencadenantes de cola requieren un mensaje real esperando en una cola respaldada por Azurite. Puede agregar un mensaje de prueba a través del Azure Storage Explorer, que se comunica con Azurite tal como lo haría con una cuenta de almacenamiento real, o mediante la extensión de almacenamiento de Azure CLI dirigida a su cadena de conexión local.
  • Los desencadenadores de tipo Blob suelen presentar retrasos a nivel local, ya que la consulta de nuevos blobs no es instantánea; esperas de varios minutos no son inusuales, a menos que se utilicen desencadenadores basados en Event Grid. Estos no funcionan bien de forma local y, por lo general, es mejor validarlos con un recurso real de Azure de bajo costo.
  • Los desencadenadores de Service Bus y Event Hub generalmente no pueden emularse en absoluto en la máquina local. Para estos casos, la mejor opción es dirigirse a un recurso real de Azure de nivel de desarrollo y económico durante las pruebas locales, haciendo referencia a una cadena de conexión separada dentro de local.settings.json.
  • Este es uno de los verdaderos problemas en el desarrollo local de Functions: algunos tipos de desencadenadores simplemente no pueden replicarse completamente en el entorno local, y tratarlos como si pudieran hacerse solo desperdicia tiempo.

    8. Depuración dentro de VS Code

    Aquí es donde la configuración local comienza a valer realmente la pena. Una vez instalada la extensión de Azure Functions:

    1. Abra la carpeta de su proyecto en VS Code.
    2. Coloque puntos de interrupción donde los necesite dentro del código desencadenante.
    3. Pulse F5 — VS Code se encarga de compilar el proyecto, iniciar Azurite si está configurado para ello, lanzar el host de Functions y conectar el depurador, todo sin pasos manuales.

    Los archivos .vscode/launch.json y tasks.json generados automáticamente coordinan todo esto en segundo plano. Si los puntos de interrupción no detienen la ejecución, verifique que la configuración preLaunchTask dentro de launch.json esté realmente reconstruyendo su código antes de que se inicie el host; una compilación obsoleta es una causa sutil pero frecuente por la que parece que los puntos de interrupción son ignorados.

    9. Errores comunes y cómo solucionarlos realmente

    Esa fila en particular causa más confusión a los desarrolladores que cualquier defecto real en el propio entorno de ejecución de Functions. local.settings.json se deja intencionadamente fuera del paquete de despliegue por razones de seguridad, lo que significa que cualquier valor secreto o de configuración almacenado allí no se transferirá automáticamente junto con la aplicación a Azure; debe agregarse por separado, ya sea a través del portal de Azure o mediante herramientas CLI/pipeline.

    10. Ejecutar Functions localmente con Docker

    Si su equipo desea que los entornos locales y de producción sean idénticos, o si necesita validar un contenedor Linux personalizado, Azure Functions también ofrece una opción basada en Docker:

    func init MyFunctionApp --worker-runtime node --docker
    cd MyFunctionApp
    docker build -t my-function-app .
    docker run -p 7071:80 -it my-function-app
    

    Este enfoque añade más carga adicional en comparación con un simple func start, pero elimina todo tipo de problemas del tipo “funciona en mi máquina”, especialmente para equipos que distribuyen aplicaciones en contenedores personalizados o que necesitan una consistencia estricta a nivel del sistema operativo con lo que se ejecuta en producción.

    11. Gestionar secretos y variables de entorno de la manera correcta

    No incluya local.settings.json en el control de versiones. Está diseñado para almacenar cadenas de conexión reales durante el desarrollo, y los proyectos con estructura predefinida lo excluyen de git por defecto; verifique su .gitignore para estar seguro. Al trabajar en equipo:

    • Comparta una versión modificada, algo como local.settings.json.example, rellena con valores de ejemplo en lugar de secretos reales.
  • Una vez que pase de las pruebas puramente locales, confíe en las referencias de Azure Key Vault para cualquier información sensible.
  • En los pipelines de CI, transmita la configuración a través de variables de entorno en lugar de guardar un archivo de configuraciones real en el repositorio.
  • 12. Mejores prácticas para un ciclo de desarrollo local sin problemas

    • Inicie Azurite antes de lanzar el host de Functions: el orden es importante, ya que algunos desencadenantes verifican el almacenamiento tan pronto como se inician.
    • Defina con precisión la versión de Core Tools que utiliza su equipo, ya sea en sus documentos o en un script de configuración. Las diferencias de versión entre las máquinas representan una carga silenciosa pero real para la productividad.
    • Ejecute func start --verbose cada vez que esté resolviendo un problema de inicio: el nivel de registro por defecto a menudo oculta la causa real.
    • Reinicie el host cada vez que edite host.json o local.settings.json; ninguno de estos archivos se actualiza mediante el recarga en caliente.
    • Tenga disponible un recurso de nivel bajo en Azure para tipos de desencadenantes como Service Bus o Event Grid, que no pueden replicarse completamente en un emulador local.

    Consideraciones finales

    El desarrollo local para Azure Functions no está fundamentalmente defectuoso; simplemente se compone de varios elementos interconectados que deben mantenerse alineados, y la mayoría de las guías omiten precisamente las partes que causan los verdaderos problemas: la emulación correcta del almacenamiento, las incompatibilidades en el tiempo de ejecución de los trabajadores y los límites entre lo que su configuración local puede simular y lo que no. Una vez que comprenda estos tres aspectos, func start deja de parecer un riesgo y se convierte en solo otro comando rutinario.

    Si hay un solo hábito que vale la pena adoptar de todo esto, es este: siempre confirme si Azurite está realmente en ejecución antes de comenzar a solucionar cualquier otro problema. Ese único descuido desperdicia silenciosamente más tiempo que cualquier error real en su código de función.

    Lecturas relacionadas

  • Arreglar errores de manejo de errores Async/Await en código producción Node.js — Conozca cinco errores comunes al manejar errores con async/await en JavaScript y Node.js que causan fallos silenciosos y condiciones de carrera, además de soluciones concretas.
  • Arreglar el error de biblioteca faltante libssl.so.1.1 en Prisma en Alpine Docker — Entienda por qué el motor de consultas de Prisma se cae en imágenes Docker basadas en Alpine debido a un error de libssl faltante, y cómo solucionarlo de forma permanente.