Compartir a través de


Guía para desarrolladores de Azure Functions Node.js

Esta guía es una introducción al desarrollo de Azure Functions mediante JavaScript o TypeScript. En el artículo se supone que ya ha leído la guía para desarrolladores Azure Functions.

Importante

El contenido de este artículo cambia en función de la elección del modelo de programación de Node.js en el selector de la parte superior de esta página. La versión que elija debe coincidir con la versión del paquete npm que usa en la aplicación. Si no tiene ese paquete en la lista , el valor predeterminado es v3. Obtenga más información sobre las diferencias entre v3 y v4 en la guía de migración.

Como desarrollador de Node.js, puede que también le interese uno de los siguientes artículos:

Introducción Conceptos Aprendizaje guiado
  • Guía del desarrollador
  • Opciones de hospedaje
  • Consideraciones de rendimiento
  • Creación de aplicaciones sin servidor
  • Refactorización de las API de Node.js y Express para las API sin servidor

Consideraciones

  • El modelo de programación Node.js no debe confundirse con el entorno de ejecución de Azure Functions:
    • Modelo de programación: define cómo crea el código y es específico de JavaScript y TypeScript.
    • Runtime: define el comportamiento subyacente de Azure Functions y se comparte en todos los lenguajes.
  • La versión del modelo de programación está estrictamente vinculada a la versión del paquete npm de . Se versiona independientemente del entorno de ejecución. Tanto el entorno de ejecución como el modelo de programación usan el número 4 como versión principal más reciente, pero es una coincidencia.
  • No puede mezclar los modelos de programación de las versiones 3 y 4 en la misma aplicación de funciones. En cuanto registre una función de la versión 4 en la aplicación, se omiten las funciones de la versión 3 registradas en los archivos function.json.

Versiones compatibles

En la tabla siguiente se muestra cada versión del modelo de programación de Node.js junto con sus versiones compatibles del entorno de ejecución de Azure Functions y Node.js.

Versión del modelo de programación Nivel de soporte técnico Versión del runtime de Functions Versión del Node.js Descripción
4.x Disponibilidad general 4.25+ 22.x 20.x, 18.x Admite una estructura de archivos flexible y un enfoque centrado en código para desencadenadores y enlaces.
3.x Disponibilidad general 4.x 20.x, 18.x, 16.x, 14.x Requiere una estructura de archivos específica con los desencadenadores y enlaces declarados en un archivo "function.json"
2.x N/D 3.x 14.x, 12.x, 10.x Llegó al final del soporte técnico el 13 de diciembre de 2022. Consulte Versiones de Functions para obtener más información.
1.x N/D 2.x 10.x, 8.x Llegó al final del soporte técnico el 13 de diciembre de 2022. Consulte Versiones de Functions para obtener más información.

Estructura de carpetas

  • JavaScript
  • TypeScript

La estructura de carpetas necesaria para un proyecto de JavaScript se parece al ejemplo siguiente:

<project_root>/
 | - .vscode/
 | - node_modules/
 | - myFirstFunction/
 | | - index.js
 | | - function.json
 | - mySecondFunction/
 | | - index.js
 | | - function.json
 | - .funcignore
 | - host.json
 | - local.settings.json
 | - package.json

La carpeta de proyecto principal, project_root, puede contener los siguientes archivos:

  • .vscode/: (Opcional) Contiene la configuración de Visual Studio Code almacenada. Para obtener más información, consulte Visual Studio Code settings.
  • myFirstFunction/function.json: contiene la configuración del desencadenador, las entradas y las salidas de la función. El nombre del directorio determina el nombre de la función.
  • myFirstFunction/index.js: almacena el código de la función. Para cambiar esta ruta de acceso de archivo predeterminada, consulte Uso de scriptFile.
  • .funcignore: (Opcional) Declara archivos que no deben publicarse en Azure. Normalmente, este archivo contiene .vscode/ para omitir la configuración del editor, test/ para omitir los casos de prueba y local.settings.json para evitar la publicación de la configuración de la aplicación local.
  • host.json: contiene las opciones de configuración global que afectan a todas las funciones de una instancia de aplicación de funciones. Este archivo se publica en Azure. No todas las opciones se admiten cuando se ejecuta localmente. Para más información, consulte host.json.
  • local.settings.json: se usa para almacenar las cadenas de conexión y la configuración de la aplicación cuando la ejecución se realiza a nivel local. Este archivo no se publica en Azure. Para más información, consulte local.settings.file.
  • package.json: contiene opciones de configuración como una lista de dependencias de paquete, el punto de entrada principal y los scripts.
  • JavaScript
  • TypeScript

La estructura de carpetas recomendada para un proyecto de JavaScript en Azure Functions tiene la siguiente apariencia:

<project_root>/
 | - .vscode/
 | - node_modules/
 | - src/
 | | - functions/
 | | | - myFirstFunction.js
 | | | - mySecondFunction.js
 | - test/
 | | - functions/
 | | | - myFirstFunction.test.js
 | | | - mySecondFunction.test.js
 | - .funcignore
 | - host.json
 | - local.settings.json
 | - package.json

La carpeta de proyecto principal, project_root, puede contener los siguientes archivos:

  • .vscode/: (Opcional) Contiene la configuración de Visual Studio Code almacenada. Para obtener más información, consulte Visual Studio Code settings.
  • src/functions/: la ubicación predeterminada para todas las funciones y sus desencadenadores y enlaces relacionados.
  • test/: (opcional) contiene los casos de prueba de la aplicación de funciones.
  • .funcignore: (Opcional) Declara archivos que no deben publicarse en Azure. Normalmente, este archivo contiene .vscode/ para omitir la configuración del editor, test/ para omitir los casos de prueba y local.settings.json para evitar la publicación de la configuración de la aplicación local.
  • host.json: contiene las opciones de configuración global que afectan a todas las funciones de una instancia de aplicación de funciones. Este archivo se publica en Azure. No todas las opciones se admiten cuando se ejecuta localmente. Para más información, consulte host.json.
  • local.settings.json: se usa para almacenar las cadenas de conexión y la configuración de la aplicación cuando la ejecución se realiza a nivel local. Este archivo no se publica en Azure. Para más información, consulte local.settings.file.
  • package.json: contiene opciones de configuración como una lista de dependencias de paquete, el punto de entrada principal y los scripts.

Registro de una función

El modelo v3 registra una función según la existencia de dos archivos. En primer lugar, necesita un archivo ubicado en una carpeta un nivel por debajo de la raíz de la aplicación. En segundo lugar, necesitará un archivo JavaScript que exporte la función. De forma predeterminada, el modelo busca un archivo en la misma carpeta que . Si usa TypeScript, deberá usar la propiedad en para que apunte al archivo JavaScript compilado. Para personalizar la ubicación del archivo o el nombre de exportación de la función, consulte la configuración del punto de entrada de la función.

La función que exporta siempre debe declararse como en el modelo v3. Puede exportar una función sincrónica, pero debe llamar a para indicar que la función se ha completado, lo que está en desuso y no se recomienda.

La función recibe una invocación como primer argumento y las entradas como argumentos restantes.

El ejemplo siguiente es una función simple que registra que se ha desencadenado y responde con :

  • JavaScript
  • TypeScript
{
  "bindings": [
    {
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "authLevel": "anonymous",
      "methods": ["get", "post"]
    },
    {
      "type": "http",
      "direction": "out",
      "name": "res"
    }
  ]
}
module.exports = async function (context, request) {
  context.log("Http function was triggered.");
  context.res = { body: "Hello, world!" };
};

El modelo de programación carga las funciones en función del campo de . Puede establecer el campo en un único archivo o en varios archivos mediante un patrón global. La siguiente tabla muestra valores de ejemplo para el campo :

  • JavaScript
  • TypeScript
Ejemplo Descripción
src/index.js Registrar funciones desde un único archivo raíz.
src/functions/*.js Registre cada función desde su propio archivo.
src/{index.js,functions/*.js} Combinación en la que se registra cada función desde su propio archivo, pero todavía tiene un archivo raíz para el código general de nivel de aplicación.

Para registrar una función, debe importar el objeto desde el módulo npm y llamar al método específico del tipo de desencadenador. El primer argumento al registrar una función es el nombre de la función. El segundo argumento es un objeto que especifica la configuración del desencadenador, el controlador y cualquier otra entrada o salida. En algunos casos en los que la configuración del desencadenador no sea necesaria, puede pasar el controlador directamente como segundo argumento en lugar de un objeto .

El registro de una función se puede realizar desde cualquier archivo del proyecto, siempre y cuando ese archivo se cargue (directa o indirectamente) en función del campo del archivo . La función debe registrarse en un ámbito global porque no se pueden registrar funciones una vez que se inicien las ejecuciones.

El ejemplo siguiente es una función simple que registra que se ha desencadenado y responde con :

  • JavaScript
  • TypeScript
const { app } = require("@azure/functions");

app.http("helloWorld1", {
  methods: ["POST", "GET"],
  handler: async (request, context) => {
    context.log("Http function was triggered.");
    return { body: "Hello, world!" };
  },
});

Entradas y salidas

La función es necesaria para tener exactamente una entrada principal denominada desencadenador. También puede tener entradas secundarias o salidas. Las entradas y salidas se configuran en los archivos y también se conocen como enlaces.

Entradas

Las entradas son enlaces con establecido en . La principal diferencia entre un desencadenador y una entrada secundaria es que para un desencadenador finaliza en ; por ejemplo, el tipo en comparación con el tipo . La mayoría de las funciones solo usan un desencadenador y no se admiten muchos tipos de entrada secundarios.

Se puede acceder a las entradas de varias maneras:

  • [Recomendado] Como argumentos pasados a la función: use los argumentos en el mismo orden en que se definen en . La propiedad definida en no tiene que coincidir con el nombre de tu argumento; sin embargo, recomendamos hacerlo por razones de organización.

    • JavaScript
    • TypeScript
    module.exports = async function (context, myTrigger, myInput, myOtherInput) { ... };
    

  • Como propiedades de : use la clave que coincide con la propiedad definida en .

    • JavaScript
    • TypeScript
    module.exports = async function (context) {
      context.log("This is myTrigger: " + context.bindings.myTrigger);
      context.log("This is myInput: " + context.bindings.myInput);
      context.log("This is myOtherInput: " + context.bindings.myOtherInput);
    };
    

Salidas

Las salidas son enlaces con establecido en y se pueden establecer de varias maneras:

  • [Recomendado para una salida única] Devuelva el valor directamente: si usa una función asincrónica, puede devolver el valor directamente. Debe cambiar la propiedad del enlace de salida a en como en el ejemplo siguiente:

    {
      "name": "$return",
      "type": "http",
      "direction": "out"
    }
    
    • JavaScript
    • TypeScript
    module.exports = async function (context, request) {
      return {
        body: "Hello, world!",
      };
    };
    

  • [Recomendado para varias salidas] Devuelva un objeto que contenga todas las salidas: si usa una función asincrónica, puede devolver un objeto con una propiedad que coincida con el nombre de cada enlace de . En el ejemplo siguiente se usan enlaces de salida denominados "httpResponse" y "queueOutput":

    {
        "name": "httpResponse",
        "type": "http",
        "direction": "out"
    },
    {
        "name": "queueOutput",
        "type": "queue",
        "direction": "out",
        "queueName": "helloworldqueue",
        "connection": "storage_APPSETTING"
    }
    
    • JavaScript
    • TypeScript
    module.exports = async function (context, request) {
      let message = "Hello, world!";
      return {
        httpResponse: {
          body: message,
        },
        queueOutput: message,
      };
    };
    

  • Establezca valores en : si no usa una función asincrónica o no quiere usar las opciones anteriores, puede establecer los valores directamente en , en los que la clave coincide con el nombre del enlace. En el ejemplo siguiente se usan enlaces de salida denominados "httpResponse" y "queueOutput":

    {
        "name": "httpResponse",
        "type": "http",
        "direction": "out"
    },
    {
        "name": "queueOutput",
        "type": "queue",
        "direction": "out",
        "queueName": "helloworldqueue",
        "connection": "storage_APPSETTING"
    }
    
    • JavaScript
    • TypeScript
    module.exports = async function (context, request) {
      let message = "Hello, world!";
      context.bindings.httpResponse = {
        body: message,
      };
      context.bindings.queueOutput = message;
    };
    

Tipo de datos de enlaces

Puede usar la propiedad en un enlace de entrada para cambiar el tipo de entrada. Sin embargo, el enfoque tiene algunas limitaciones:

  • En Node.js, solo se admiten y ( no).
  • En el caso de las entradas HTTP, se omite la propiedad . En su lugar, use propiedades en el objeto para obtener el cuerpo en el formato que quiera. Para obtener más información, consulte Solicitud HTTP.

En el ejemplo siguiente de un desencadenador de cola de almacenamiento, el tipo predeterminado de es , pero si se establece en , el tipo cambia a de Node.js.

{
  "name": "myQueueItem",
  "type": "queueTrigger",
  "direction": "in",
  "queueName": "helloworldqueue",
  "connection": "storage_APPSETTING",
  "dataType": "binary"
}
  • JavaScript
  • TypeScript
const { Buffer } = require("node:buffer");

module.exports = async function (context, myQueueItem) {
  if (typeof myQueueItem === "string") {
    context.log("myQueueItem is a string");
  } else if (Buffer.isBuffer(myQueueItem)) {
    context.log("myQueueItem is a buffer");
  }
};

La función es necesaria para tener exactamente una entrada principal denominada desencadenador. También puede tener entradas secundarias, una salida principal denominada salida de retorno o salidas secundarias. Las entradas y salidas también se conocen como enlaces fuera del contexto del modelo de programación de Node.js. Antes de la versión v4 del modelo, estos enlaces se configuraron en archivos .

Entrada del desencadenador

El desencadenador es la única entrada o salida necesaria. Para la mayoría de los tipos de desencadenador, se registra una función mediante un método en el objeto denominado después del tipo de desencadenador. Puede especificar la configuración específica del desencadenador directamente en el argumento . Por ejemplo, un desencadenador HTTP permite especificar una ruta. Durante la ejecución, el valor correspondiente a este desencadenador se pasa como primer argumento al controlador.

  • JavaScript
  • TypeScript
const { app } = require('@azure/functions');

app.http('helloWorld1', {
    route: 'hello/world',
    handler: async (request, context) => {
        ...
    }
});

Salida de devolución

La salida de devolución es opcional y, en algunos casos, está configurada de forma predeterminada. Por ejemplo, un desencadenador HTTP registrado con está configurado para devolver automáticamente una salida de respuesta HTTP. Para la mayoría de los tipos de salida, especifique la configuración de devolución en el argumento con la ayuda del objeto exportado desde el módulo . Durante la ejecución, esta salida se establece devolviendo desde el controlador.

En el ejemplo siguiente se usa un desencadenador de temporizador y una salida de cola de almacenamiento:

  • JavaScript
  • TypeScript
const { app, output } = require('@azure/functions');

app.timer('timerTrigger1', {
    schedule: '0 */5 * * * *',
    return: output.storageQueue({
        connection: 'storage_APPSETTING',
        ...
    }),
    handler: (myTimer, context) => {
        return { hello: 'world' }
    }
});

Entradas y salidas adicionales

Además del desencadenador y la devolución, puede especificar entradas o salidas adicionales en el argumento al registrar una función. Los objetos y exportados desde el módulo proporcionan métodos específicos del tipo para ayudar a construir la configuración. Durante la ejecución, obtiene o establece los valores con o , pasando el objeto de configuración original como primer argumento.

El ejemplo siguiente es una función desencadenada por una cola de almacenamiento, con una entrada de blob de almacenamiento adicional que se copia en una salida de blob adicional. El mensaje de cola debe ser el nombre de un archivo y reemplaza como nombre de blob que se va a copiar, con la ayuda de una expresión de enlace.

  • JavaScript
  • TypeScript
const { app, input, output } = require("@azure/functions");

const blobInput = input.storageBlob({
  connection: "storage_APPSETTING",
  path: "helloworld/{queueTrigger}",
});

const blobOutput = output.storageBlob({
  connection: "storage_APPSETTING",
  path: "helloworld/{queueTrigger}-copy",
});

app.storageQueue("copyBlob1", {
  queueName: "copyblobqueue",
  connection: "storage_APPSETTING",
  extraInputs: [blobInput],
  extraOutputs: [blobOutput],
  handler: (queueItem, context) => {
    const blobInputValue = context.extraInputs.get(blobInput);
    context.extraOutputs.set(blobOutput, blobInputValue);
  },
});

Entradas y salidas genéricas

Los objetos , , y exportados por el módulo proporcionan métodos específicos del tipo para la mayoría de los tipos. Para todos los tipos que no se admiten, se proporciona un método para que pueda especificar manualmente la configuración. El método también se puede usar si desea cambiar la configuración predeterminada proporcionada por un método específico del tipo.

El ejemplo siguiente es una función simple desencadenada por HTTP mediante métodos genéricos en lugar de métodos específicos del tipo.

  • JavaScript
  • TypeScript
const { app, output, trigger } = require("@azure/functions");

app.generic("helloWorld1", {
  trigger: trigger.generic({
    type: "httpTrigger",
    methods: ["GET", "POST"],
  }),
  return: output.generic({
    type: "http",
  }),
  handler: async (request, context) => {
    context.log(`Http function processed request for url "${request.url}"`);

    return { body: `Hello, world!` };
  },
});

Tipos de SDK

Ahora, varias extensiones de enlace permiten trabajar directamente con los tipos de Azure SDK.

Almacenamiento de blobs de Azure

La funcionalidad de enlaces de SDK en Azure Functions permite trabajar directamente con los tipos de SDK de Blob Storage de Azure, como BlobClient y ContainerClient en lugar de datos sin procesar. Esto proporciona acceso completo a todos los métodos del SDK al trabajar con blobs.

Para configurar el proyecto para que funcione con los tipos de SDK:

  1. Agregue los paquetes de vista previa de extensión al archivo del proyecto, que debe incluir al menos estos paquetes:
"dependencies": {
  "@azure/functions": "4.7.2-preview",
  "@azure/functions-extensions-blob": "0.2.0-preview"
},
  1. Agregue a para admitir tipos de streaming:
import { app } from '@azure/functions';

app.setup({
    enableHttpStream: true,
});

En este ejemplo se muestra cómo obtener el BlobClient de un desencadenador de Storage Blob y del enlace de entrada en un desencadenador HTTP:

import "@azure/functions-extensions-blob"; // This is the mandatory first import for SDK binding
import { StorageBlobClient } from "@azure/functions-extensions-blob";
import { app, InvocationContext } from "@azure/functions";

export async function storageBlobTrigger(
  blobStorageClient: StorageBlobClient, // SDK binding provides this client
  context: InvocationContext
): Promise<void> {
  context.log(`Blob trigger processing: ${context.triggerMetadata.name}`);

  // Access to full SDK capabilities
  const blobProperties = await blobStorageClient.blobClient.getProperties();
  context.log(`Blob size: ${blobProperties.contentLength}`);

  // Download blob content
  const downloadResponse = await blobStorageClient.blobClient.download();
  context.log(`Content: ${downloadResponse}`);
}

// Register the function
app.storageBlob("storageBlobTrigger", {
  path: "snippets/{name}",
  connection: "AzureWebJobsStorage",
  sdkBinding: true, // Enable SDK binding
  handler: storageBlobTrigger,
});

En este ejemplo se explica cómo obtener el a través de un enlace de entrada de Storage Blob mediante un desencadenador HTTP:

import "@azure/functions-extensions-blob"; // This is the mandatory first import for SDK binding
import { StorageBlobClient } from "@azure/functions-extensions-blob";
import {
  app,
  HttpRequest,
  HttpResponseInit,
  input,
  InvocationContext,
} from "@azure/functions";

const blobInput = input.storageBlob({
  path: "snippets",
  connection: "AzureWebJobsStorage",
  sdkBinding: true,
});

export async function listBlobs(
  request: HttpRequest,
  context: InvocationContext
): Promise<HttpResponseInit> {
  // Get input binding for a specific container
  const storageBlobClient = context.extraInputs.get(
    blobInput
  ) as StorageBlobClient;

  // List all blobs in the container
  const blobs = [];
  for await (const blob of storageBlobClient.containerClient.listBlobsFlat()) {
    blobs.push(blob.name);
  }

  return { jsonBody: { blobs } };
}

app.http("listBlobs", {
  methods: ["GET"],
  authLevel: "function",
  extraInputs: [blobInput],
  handler: listBlobs,
});

Tenga en cuenta estas consideraciones al trabajar con tipos de SDK:

  • Siempre tenga primero en sus archivos para asegurarse de que se ejecutan efectos secundarios.
  • Establezca en la configuración de enlace.
  • Use el tipo de cliente adecuado para la operación:
    • para operaciones en un único blob
    • para operaciones en un contenedor
  • Maneje los errores adecuadamente con los bloques
  • En el caso de las operaciones de blobs grandes, considere la posibilidad de usar métodos de streaming para evitar problemas de memoria.

Para obtener más información, consulte estas muestras de enlaces del SDK de Blob Storage para Node.js: para obtener más ejemplos sobre cómo incorporar enlaces del SDK de Blob en su aplicación de funciones.

Azure Service Bus

En este ejemplo se usa el tipo de SDK ServiceBusReceivedMessage obtenido de ServiceBusMessageContext proporcionado por el desencadenador de Service Bus:

import '@azure/functions-extensions-servicebus'; // Ensure the Service Bus extension is imported
import { app, InvocationContext } from '@azure/functions';
import { ServiceBusMessageContext } from '@azure/functions-extensions-servicebus';
import { parseBody } from '../servicebus-helpers'; // Interim helper until #50 lands

// This sample uses sdkBinding = true with manual message completion.
// With v0.4.0, message.body is returned as a raw Buffer instead of auto-parsed object.
export async function serviceBusQueueTrigger(
    serviceBusMessageContext: ServiceBusMessageContext,
    context: InvocationContext
): Promise<void> {
    const message = serviceBusMessageContext.messages[0];

    // v0.4.0: message.body is a Buffer — use parseBody<T>() helper for one-line parsing
    const bodyData = parseBody(message);
    context.log('Parsed message body:', bodyData);

    // Get current retry count from custom properties, default to 0
    const currentRetryCount = message.applicationProperties?.retryCnt
        ? parseInt(message.applicationProperties.retryCnt as string)
        : 0;
    context.log(`Current retry count: ${currentRetryCount}`);

    if (currentRetryCount >= 3) {
        // After 3 retries, complete the message to remove it from the queue
        context.log(`Maximum retry count (3) reached. Completing message to prevent infinite loop.`);
        await serviceBusMessageContext.actions.complete(message);
        context.log('Message completed after maximum retries');
    } else {
        // Abandon with updated retry count
        const newRetryCount = currentRetryCount + 1;
        const propertiesToModify = {
            retryCnt: newRetryCount.toString(),
            lastRetryTime: new Date().toISOString(),
            errorMessage: 'Processing failed',
        };

        context.log(`Abandoning message with retry count: ${newRetryCount}`);
        await serviceBusMessageContext.actions.abandon(message, propertiesToModify);
    }

    context.log('triggerMetadata: ', context.triggerMetadata);
}

app.serviceBusQueue('serviceBusQueueTrigger1', {
    connection: 'ServiceBusConnection',
    queueName: 'testqueue',

Para obtener otro ejemplo del uso de tipos de SDK, consulte el ejemplo de estrategia de retroceso exponencial .

Contexto de invocación

Cada invocación de la función recibe un objeto de invocación , que se usa para leer entradas, establecer salidas, escribir en registros y leer varios metadatos. En el modelo v3, el objeto de contexto siempre es el primer argumento pasado al controlador.

El objeto tiene las siguientes propiedades:

Propiedad Descripción
invocationId Id. de la invocación de la función actual.
executionContext Consulte Contexto de ejecución.
bindings Consulte Enlaces.
bindingData Metadatos sobre la entrada del desencadenador para esta invocación, sin incluir el propio valor. Por ejemplo, un desencadenador del centro de eventos tiene una propiedad .
traceContext Contexto para el seguimiento distribuido. Para más información, consulte .
bindingDefinitions Configuración de las entradas y salidas, tal como se define en .
req Consulte Solicitud HTTP.
res Consulte Respuesta HTTP.

context.executionContext

El objeto tiene las siguientes propiedades:

Propiedad Descripción
invocationId Id. de la invocación de la función actual.
functionName Nombre de la función invocada. EL nombre de la carpeta que contiene el archivo determina el nombre de la función.
functionDirectory Carpeta que contiene el archivo .
retryContext Consulte Contexto de reintento.

context.executionContext.retryContext

El objeto tiene las siguientes propiedades:

Propiedad Descripción
retryCount Número que representa el intento de reintento actual.
maxRetryCount Número máximo de veces que se reintenta una ejecución. Un valor de significa que se reintentará indefinidamente.
exception Excepción que provocó el reintento.

context.bindings

El objeto se usa para leer entradas o establecer salidas. El ejemplo siguiente es un desencadenador de cola de almacenamiento, que usa para copiar una entrada de blob de almacenamiento a una salida de blob de almacenamiento. El contenido del mensaje de la cola reemplaza como nombre de archivo que se va a copiar, con la ayuda de una expresión de enlace.

{
    "name": "myQueueItem",
    "type": "queueTrigger",
    "direction": "in",
    "connection": "storage_APPSETTING",
    "queueName": "helloworldqueue"
},
{
    "name": "myInput",
    "type": "blob",
    "direction": "in",
    "connection": "storage_APPSETTING",
    "path": "helloworld/{queueTrigger}"
},
{
    "name": "myOutput",
    "type": "blob",
    "direction": "out",
    "connection": "storage_APPSETTING",
    "path": "helloworld/{queueTrigger}-copy"
}
  • JavaScript
  • TypeScript
module.exports = async function (context, myQueueItem) {
  const blobValue = context.bindings.myInput;
  context.bindings.myOutput = blobValue;
};

context.done

Este método está en desuso. Antes de que se admitieran las funciones asincrónicas, se indicaba que la función había terminado mediante una llamada a :

  • JavaScript
  • TypeScript
module.exports = function (context, request) {
  context.log("this pattern is now deprecated");
  context.done();
};

Recomendamos que quite la llamada a y marcar la función como asincrónica para que devuelva una promesa (incluso si no aplica a nada). Tan pronto como finalice la función (en otras palabras, se resuelva la promesa devuelta), el modelo v3 sabrá que la función ha terminado.

  • JavaScript
  • TypeScript
module.exports = async function (context, request) {
  context.log("you don't need context.done or an awaited call");
};

Cada invocación de la función recibe un objeto de invocación, con información adicional sobre el contexto y los métodos usados para el registro. En el modelo v4, el objeto suele ser el segundo argumento pasado al controlador.

La clase tiene las siguientes propiedades:

Propiedad Descripción
invocationId Id. de la invocación de la función actual.
functionName El nombre de la función.
extraInputs Se usa para obtener los valores de entradas adicionales. Para obtener más información, consulte Entradas y salidas adicionales.
extraOutputs Se usa para establecer los valores de salidas adicionales. Para obtener más información, consulte Entradas y salidas adicionales.
retryContext Consulte Contexto de reintento.
traceContext Contexto para el seguimiento distribuido. Para más información, consulte .
triggerMetadata Metadatos sobre la entrada del desencadenador para esta invocación, sin incluir el propio valor. Por ejemplo, un desencadenador del centro de eventos tiene una propiedad .
options Las opciones usadas al registrar la función, después de que se hayan validado y con los valores predeterminados especificados explícitamente.

Contexto de reintento

El objeto tiene las siguientes propiedades:

Propiedad Descripción
retryCount Número que representa el intento de reintento actual.
maxRetryCount Número máximo de veces que se reintenta una ejecución. Un valor de significa que se reintentará indefinidamente.
exception Excepción que provocó el reintento.

Para más información, consulte .

Registro

En Azure Functions, se recomienda usar context.log() para escribir registros. Azure Functions se integra con Azure Application Insights para capturar mejor los registros de la aplicación de funciones. Application Insights, que forma parte de Azure Monitor, proporciona instalaciones para la recopilación, la representación visual y el análisis de los registros de aplicación y las salidas de seguimiento. Para obtener más información, consulte monitoring Azure Functions.

Nota:

Si usa el método alternativo de Node.js, se realiza un seguimiento de esos registros en el nivel de aplicación y no se asociará a ninguna función específica. Se recomienda encarecidamente que use para el registro en lugar de para que todos los registros estén asociados a una función específica.

En el ejemplo siguiente se escribe un registro en el nivel de "información" predeterminado, incluido el id. de invocación:

  • JavaScript
  • TypeScript
context.log(`Something has happened. Invocation ID: "${context.invocationId}"`);

Niveles de registro

Además del método predeterminado, están disponibles los siguientes métodos para permitirle escribir registros en niveles específicos:

Método Descripción
context.log.error() Escribe un evento de nivel de error en los registros.
context.log.warn() Escribe un evento de nivel de advertencia en los registros.
context.log.info() Escribe un evento de nivel de información en los registros.
context.log.verbose() Escribe un evento de nivel de seguimiento en los registros.
Método Descripción
context.trace() Escribe un evento de nivel de seguimiento en los registros.
context.debug() Escribe un evento de nivel de depuración en los registros.
context.info() Escribe un evento de nivel de información en los registros.
context.warn() Escribe un evento de nivel de advertencia en los registros.
context.error() Escribe un evento de nivel de error en los registros.

Configurar el nivel de registro

Azure Functions permite definir el nivel de umbral que se usará al realizar el seguimiento y la visualización de registros. Para establecer el umbral, use la propiedad del archivo . Esta propiedad permite definir un nivel predeterminado aplicado a todas las funciones o un umbral para cada función individual. Para obtener más información, consulte Cómo configurar la supervisión para Azure Functions.

Seguimiento de datos personalizados

De forma predeterminada, Azure Functions escribe las salidas como seguimientos en Application Insights. Para obtener más control, puede usar el SDK de Application Insights Node.js para enviar registros, métricas y dependencias personalizados a la instancia de Application Insights.

Nota:

Los métodos del SDK de Application Insights Node.js pueden cambiar con el tiempo. Puede haber diferencias menores de sintaxis de los ejemplos que se muestran aquí. Para ver los ejemplos de uso de API más recientes, consulte la documentación del SDK de Application Insights Node.js.

Para el seguimiento distribuido en el modelo de programación de Node.js v4, puede usar el paquete en lugar del SDK de Application Insights. Este paquete proporciona instrumentación automática basada en OpenTelemetry para Azure Functions. Para obtener más información, consulte el repositorio OpenTelemetry Azure Functions Instrumentation for Node.js GitHub.

  • JavaScript
  • TypeScript
const appInsights = require("applicationinsights");
appInsights.setup();
const client = appInsights.defaultClient;

module.exports = async function (context, request) {
  // Use this with 'tagOverrides' to correlate custom logs to the parent function invocation.
  var operationIdOverride = {
    "ai.operation.id": context.traceContext.traceparent,
  };

  client.trackEvent({
    name: "my custom event",
    tagOverrides: operationIdOverride,
    properties: { customProperty2: "custom property value" },
  });
  client.trackException({
    exception: new Error("handled exceptions can be logged with this method"),
    tagOverrides: operationIdOverride,
  });
  client.trackMetric({
    name: "custom metric",
    value: 3,
    tagOverrides: operationIdOverride,
  });
  client.trackTrace({
    message: "trace message",
    tagOverrides: operationIdOverride,
  });
  client.trackDependency({
    target: "http://dbname",
    name: "select customers proc",
    data: "SELECT * FROM Customers",
    duration: 231,
    resultCode: 0,
    success: true,
    dependencyTypeName: "ZSQL",
    tagOverrides: operationIdOverride,
  });
  client.trackRequest({
    name: "GET /customers",
    url: "http://myserver/customers",
    duration: 309,
    resultCode: 200,
    success: true,
    tagOverrides: operationIdOverride,
  });
};

El parámetro establece en el identificador de invocación de la función. Esta configuración le permite correlacionar todos los registros personalizados y generados automáticamente para una determinada invocación de función.

Desencadenadores HTTP

Los desencadenadores HTTP y de webhook usan objetos de solicitud y respuesta para representar mensajes HTTP.

Los desencadenadores HTTP y de webhook usan objetos y para representar mensajes HTTP. Las clases representan un subconjunto del estándar de captura, mediante el paquete de Node.js.

Solicitud HTTP

Se puede acceder a una solicitud de varias maneras:

  • Como segundo argumento de la función:

    • JavaScript
    • TypeScript
    module.exports = async function (context, request) {
        context.log(`Http function processed request for url "${request.url}"`);
    

  • Desde la propiedad :

    • JavaScript
    • TypeScript
    module.exports = async function (context, request) {
        context.log(`Http function processed request for url "${context.req.url}"`);
    

  • Desde los enlaces de entrada con nombre: esta opción funciona igual que cualquier enlace no HTTP. El nombre del enlace de debe coincidir con la clave en , o "request1" en el ejemplo siguiente:

    {
      "name": "request1",
      "type": "httpTrigger",
      "direction": "in",
      "authLevel": "anonymous",
      "methods": ["get", "post"]
    }
    
    • JavaScript
    • TypeScript
    module.exports = async function (context, request) {
        context.log(`Http function processed request for url "${context.bindings.request1.url}"`);
    

El objeto tiene las siguientes propiedades:

Propiedad Tipo Descripción
method string Método de solicitud HTTP usado para invocar esta función.
url string URL de la solicitud.
headers Record<string, string> Encabezados de solicitud HTTP. Este objeto distingue entre mayúsculas y minúsculas. Se recomienda usar en su lugar, que no distingue entre mayúsculas y minúsculas.
query Record<string, string> Claves y valores de los parámetros de la cadena de consulta de la URL.
params Record<string, string> Valores y claves de parámetros de ruta.
user HttpRequestUser \| null Objeto que representa al usuario que ha iniciado sesión, ya sea a través de la autenticación de Functions, la autenticación SWA o null cuando no se inicia sesión ningún usuario de este tipo.
body Buffer \| string \| any Si el tipo de medio es "application/octet-stream" o "multipart/*", es un búfer. Si el valor es una cadena que puede analizar como JSON, es el objeto analizado. De lo contrario, es una cadena.
rawBody string Cuerpo como cadena. A pesar del nombre, esta propiedad no devuelve un búfer.
bufferBody Buffer Cuerpo como búfer.

Se puede acceder a la solicitud como primer argumento para el controlador de una función desencadenada por HTTP.

  • JavaScript
  • TypeScript
async (request, context) => {
    context.log(`Http function processed request for url "${request.url}"`);

El objeto tiene las siguientes propiedades:

Propiedad Tipo Descripción
method string Método de solicitud HTTP usado para invocar esta función.
url string URL de la solicitud.
headers Headers Encabezados de solicitud HTTP.
query URLSearchParams Claves y valores de los parámetros de la cadena de consulta de la URL.
params Record<string, string> Valores y claves de parámetros de ruta.
user HttpRequestUser \| null Objeto que representa al usuario que ha iniciado sesión, ya sea a través de la autenticación de Functions, la autenticación SWA o null cuando no se inicia sesión ningún usuario de este tipo.
body ReadableStream \| null Cuerpo como una secuencia legible.
bodyUsed boolean Valor booleano que indica si el cuerpo ya se ha leído.

Para acceder al cuerpo de una solicitud o respuesta, se pueden usar los métodos siguientes:

Método Tipo de valor devuelto
arrayBuffer() Promise<ArrayBuffer>
blob() Promise<Blob>
formData() Promise<FormData>
json() Promise<unknown>
text() Promise<string>

Nota:

Las funciones del cuerpo solo se pueden ejecutar una vez. Las llamadas posteriores se resuelven con cadenas vacías o ArrayBuffers.

Respuesta HTTP

La respuesta se puede establecer de varias maneras:

  • Establezca la propiedad :

    • JavaScript
    • TypeScript
    module.exports = async function (context, request) {
        context.res = { body: `Hello, world!` };
    

  • Devuelva la respuesta: si la función es asincrónica y establece el nombre de enlace en en , puede devolver la respuesta directamente en lugar de establecerla en .

    {
      "type": "http",
      "direction": "out",
      "name": "$return"
    }
    
    • JavaScript
    • TypeScript
    module.exports = async function (context, request) {
        return { body: `Hello, world!` };
    

  • Establezca el enlace de entrada con nombre: esta opción funciona igual que cualquier enlace no HTTP. El nombre del enlace de debe coincidir con la clave en , o "response1" en el ejemplo siguiente:

    {
      "type": "http",
      "direction": "out",
      "name": "response1"
    }
    
    • JavaScript
    • TypeScript
    module.exports = async function (context, request) {
        context.bindings.response1 = { body: `Hello, world!` };
    

  • Llame a : esta opción está en desuso. Llama implícitamente a y no se puede usar en una función asincrónica.

    • JavaScript
    • TypeScript
    module.exports = function (context, request) {
        context.res.send(`Hello, world!`);
    

Si crea un objeto nuevo al establecer la respuesta, dicho objeto debe coincidir con la interfaz , que tiene las siguientes propiedades:

Propiedad Tipo Descripción
headers (opcional) Encabezados de respuesta HTTP.
cookies (opcional) Cookies de respuesta HTTP.
body (opcional) Cuerpo de respuesta HTTP.
statusCode (opcional) Código de estado de respuesta HTTP. Si no se establece, el valor predeterminado es .
status (opcional) Igual que . Esta propiedad se ignora si está establecido.

También puede modificar el objeto sin sobrescribirlo. El objeto predeterminado usa la interfaz , que admite los métodos siguientes además de las propiedades :

Método Descripción
status() Establece el estado.
setHeader() Establece un campo de encabezado. NOTA: y también se admiten y hacen lo mismo.
getHeader() Obtiene un campo de encabezado. NOTA: también se admite y hace lo mismo.
removeHeader() Quita un encabezado.
type() Establece el encabezado "content-type".
send() Este método es desusado. Establece el cuerpo y llama a para indicar que ha terminado una función sincrónica. NOTA: también se admite y hace lo mismo.
sendStatus() Este método es desusado. Establece el código de estado y llama a para indicar que ha terminado una función sincrónica.
json() Este método es desusado. Establece el "content-type" en "application/json", establece el cuerpo y llama a para indicar que ha terminado una función sincrónica.

La respuesta se puede establecer de varias maneras:

  • Como interfaz sencilla con el tipo : esta opción es la forma más concisa de devolver respuestas.

    • JavaScript
    • TypeScript
    return { body: `Hello, world!` };
    

La interfaz tiene las propiedades siguientes:

Propiedad Tipo Descripción
body (opcional) Uno de los cuerpos de respuesta HTTP siguientes: , , , , , , , o .
jsonBody (opcional) Un cuerpo de respuesta HTTP serializable en JSON. Si se establece, la propiedad se omite en favor de esta propiedad.
status (opcional) Código de estado de respuesta HTTP. Si no se establece, el valor predeterminado es .
headers (opcional) Encabezados de respuesta HTTP.
cookies (opcional) Cookies de respuesta HTTP.
  • Como clase con tipo : esta opción proporciona métodos auxiliares para leer y modificar varias partes de la respuesta, como los encabezados.

    • JavaScript
    • TypeScript
    const response = new HttpResponse({ body: `Hello, world!` });
    response.headers.set("content-type", "application/json");
    return response;
    

La clase acepta un opcional como argumento para su constructor y tiene las siguientes propiedades:

Propiedad Tipo Descripción
status number Código de estado de respuesta HTTP.
headers Headers Encabezados de respuesta HTTP.
cookies Cookie[] Cookies de respuesta HTTP.
body ReadableStream | null Cuerpo como una secuencia legible.
bodyUsed boolean Valor booleano que indica si el cuerpo ya se ha leído.

Flujos HTTP

Los flujos HTTP son una característica que facilita el procesamiento de datos grandes, transmitir respuestas de OpenAI, ofrecer contenido dinámico y admitir otros escenarios HTTP principales. Permite transmitir solicitudes y respuestas desde puntos de conexión HTTP en la aplicación de funciones de Node.js. Use flujos HTTP en escenarios en los que la aplicación requiera intercambio en tiempo real e interacción entre el cliente y el servidor a través de HTTP. También puede usar secuencias HTTP para obtener el mejor rendimiento y confiabilidad para las aplicaciones cuando se usa HTTP.

Importante

Las secuencias HTTP no se admiten en el modelo v3. Actualice al modelo v4 para usar la característica de streaming HTTP. Los tipos y existentes del modelo de programación v4 ya admiten varias formas de controlar el cuerpo del mensaje, incluso como una secuencia.

Requisitos previos

Habilitación de secuencias

Siga estos pasos para habilitar flujos HTTP en la aplicación de funciones en Azure y en los proyectos locales:

  1. Si planea transmitir grandes cantidades de datos, modifique la configuración de FUNCTIONS_REQUEST_BODY_SIZE_LIMIT en Azure. El tamaño máximo de cuerpo predeterminado permitido es , que limita las solicitudes a un tamaño de ~100 MB.

  2. Para el desarrollo local, agregue también al archivo local.settings.json.

  3. Agregue el código siguiente a la aplicación en cualquier archivo incluido en el campo principal.

    • JavaScript
    • TypeScript
    const { app } = require("@azure/functions");
    
    app.setup({ enableHttpStream: true });
    

Ejemplos de secuencias

En este ejemplo se muestra una función desencadenada por HTTP que recibe datos a través de una solicitud HTTP POST y la función transmite estos datos a un archivo de salida especificado:

  • JavaScript
  • TypeScript
const { app } = require('@azure/functions');
const { createWriteStream } = require('fs');
const { Writable } = require('stream');

app.http('httpTriggerStreamRequest', {
    methods: ['POST'],
    authLevel: 'anonymous',
    handler: async (request, context) => {
        const writeStream = createWriteStream('<output file path>');
        await request.body.pipeTo(Writable.toWeb(writeStream));

        return { body: 'Done!' };
    },
});

En este ejemplo se muestra una función desencadenada por HTTP que transmite el contenido de un archivo como respuesta a las solicitudes HTTP GET entrantes:

  • JavaScript
  • TypeScript
const { app } = require('@azure/functions');
const { createReadStream } = require('fs');

app.http('httpTriggerStreamResponse', {
    methods: ['GET'],
    authLevel: 'anonymous',
    handler: async (request, context) => {
        const body = createReadStream('<input file path>');

        return { body };
    },
});

Para obtener una aplicación de ejemplo lista para ejecutar mediante secuencias, consulte este ejemplo en GitHub.

Consideraciones sobre secuencias

  • Use para obtener la ventaja máxima del uso de secuencias. Todavía puede seguir usando métodos como , que siempre devuelven el cuerpo como una cadena.

Enlaces

Los enlaces no se admiten en el modelo v3. Actualice al modelo v4 para usar enlaces.

Use un enlace para ejecutar código en distintos puntos del ciclo de vida de Azure Functions. Los enlaces se ejecutan en el orden en que están registrados y se pueden registrar desde cualquier archivo de la aplicación. Actualmente hay dos ámbitos de enlaces, nivel "aplicación" e "invocación".

Enlaces de invocación

Los enlaces de invocación se ejecutan una vez por cada invocación de su función, ya sea antes en un enlace o después en un enlace . De manera predeterminada, su enlace se ejecuta para todos los tipos de desencadenador, pero también puede filtrar por tipo. En el ejemplo siguiente se muestra cómo registrar un enlace de invocación y filtrar por tipo de desencadenador:

  • JavaScript
  • TypeScript
const { app } = require('@azure/functions');

app.hook.preInvocation((context) => {
    if (context.invocationContext.options.trigger.type === 'httpTrigger') {
        context.invocationContext.log(
            `preInvocation hook executed for http function ${context.invocationContext.functionName}`
        );
    }
});

app.hook.postInvocation((context) => {
    if (context.invocationContext.options.trigger.type === 'httpTrigger') {
        context.invocationContext.log(
            `postInvocation hook executed for http function ${context.invocationContext.functionName}`
        );
    }
});

El primer argumento para el controlador de enlace es un objeto de contexto específico de ese tipo de enlace.

El objeto tiene las siguientes propiedades:

Propiedad Descripción
inputs Argumentos pasados a la invocación.
functionHandler Controlador de función para la invocación. Los cambios en este valor afectan a la propia función.
invocationContext Objeto de contexto de invocación que se pasa a la función.
hookData Lugar recomendado para almacenar y compartir datos entre enlaces en el mismo ámbito. Debe usar un nombre de propiedad único para que no entre en conflicto con los datos de otros enlaces.

El objeto tiene las siguientes propiedades:

Propiedad Descripción
inputs Argumentos pasados a la invocación.
result Resultado de la función. Los cambios en este valor afectan al resultado general de la función.
error Error lanzado por la función, o null/indefinido si no hay error. Los cambios en este valor afectan al resultado general de la función.
invocationContext Objeto de contexto de invocación que se pasa a la función.
hookData Lugar recomendado para almacenar y compartir datos entre enlaces en el mismo ámbito. Debe usar un nombre de propiedad único para que no entre en conflicto con los datos de otros enlaces.

Enlaces de aplicación

Los enlaces de aplicación se ejecutan una vez por cada instancia de su aplicación, ya sea durante el inicio en un enlace de o durante la finalización en un enlace de . Los enlaces de finalización de aplicación tienen un tiempo limitado para ejecutarse y no se ejecutan en todos los escenarios.

El entorno de ejecución de Azure Functions actualmente no admite el registro de contexto fuera de una invocación. Use el paquete npm de Application Insights para registrar los datos durante los enlaces a nivel de aplicación.

En el ejemplo siguiente se registran enlaces de aplicación:

  • JavaScript
  • TypeScript
const { app } = require('@azure/functions');

app.hook.appStart((context) => {
    // add your logic here
});

app.hook.appTerminate((context) => {
    // add your logic here
});

El primer argumento para el controlador de enlace es un objeto de contexto específico de ese tipo de enlace.

El objeto tiene las siguientes propiedades:

Propiedad Descripción
hookData Lugar recomendado para almacenar y compartir datos entre enlaces en el mismo ámbito. Debe usar un nombre de propiedad único para que no entre en conflicto con los datos de otros enlaces.

El objeto tiene las siguientes propiedades:

Propiedad Descripción
hookData Lugar recomendado para almacenar y compartir datos entre enlaces en el mismo ámbito. Debe usar un nombre de propiedad único para que no entre en conflicto con los datos de otros enlaces.

Escalado y simultaneidad

De forma predeterminada, Azure Functions supervisa automáticamente la carga en la aplicación y crea más instancias de host para Node.js según sea necesario. Azure Functions usa umbrales integrados (no configurables por el usuario) para distintos tipos de desencadenadores para decidir cuándo agregar instancias, como la antigüedad de los mensajes y el tamaño de la cola para QueueTrigger. Para obtener más información, consulte Cómo funcionan los planes de consumo y Premium.

Este comportamiento de escalado es suficiente para muchas aplicaciones de Node.js. En las aplicaciones dependientes de la CPU, puede mejorar aún más el rendimiento mediante el uso de varios procesos de trabajo de lenguaje. Puede aumentar el número de procesos de trabajo por host del valor predeterminado de 1 a un máximo de 10 mediante la configuración de la aplicación FUNCTIONS_WORKER_PROCESS_COUNT. Azure Functions luego intenta distribuir uniformemente simultáneas invocaciones de funciones entre estos trabajadores. Este comportamiento hará que sea menos probable que una función que consuma mucha CPU bloquee la ejecución de otras funciones. La configuración se aplica a cada host que Azure Functions crea al escalar horizontalmente la aplicación para satisfacer la demanda.

Advertencia

Use la configuración con precaución. Ejecutar varios procesos en la misma instancia puede provocar un comportamiento impredecible y aumentar los tiempos de carga de la función. Si usa esta configuración, le recomendamos encarecidamente que desfase estas desventajas mediante la ejecución desde un archivo de paquete.

Versión de Node

Puede ver la versión actual que el entorno de tiempo de ejecución usa mediante el registro de desde cualquier función. Consulte para obtener una lista de Node.js versiones compatibles con cada modelo de programación.

Especificación de la versión de Node

La forma en que actualice la versión de Node.js depende del sistema operativo en el que se ejecuta la aplicación de funciones.

Cuando se ejecuta en Windows, la versión de Node.js se establece mediante la configuración de aplicación WEBSITE_NODE_DEFAULT_VERSION. Esta configuración se puede actualizar mediante el Azure CLI o en el portal de Azure.

Para saber más sobre las versiones de Node.js, vea las versiones compatibles.

Antes de actualizar la versión de Node.js, asegúrese de que la aplicación de funciones se ejecuta en la versión más reciente del entorno de ejecución de Azure Functions. Si necesita actualizar la versión en tiempo de ejecución, consulte Migrar aplicaciones de Azure Functions versión 3.x a la versión 4.x.

Ejecute el comando Azure CLI az functionapp config appsettings set para actualizar la versión de Node.js de la aplicación de funciones que se ejecuta en Windows:

az functionapp config appsettings set  --settings WEBSITE_NODE_DEFAULT_VERSION=~22 \
 --name <FUNCTION_APP_NAME> --resource-group <RESOURCE_GROUP_NAME>

Esto establece la configuración de la aplicación de la versión de LTS admitida de .

Una vez realizados los cambios, la aplicación de funciones se reinicia. Para saber más sobre la compatibilidad de Node.js con Functions, consulte Directiva de compatibilidad de Language Runtime.

Variables de entorno

Las variables de entorno pueden ser útiles para los secretos operativos (cadenas de conexión, claves, puntos de conexión, etc.) o para la configuración del entorno, como las variables de generación de perfiles. Puede agregar variables de entorno en los entornos locales y en la nube y acceder a ellas a través de en el código de la función.

En el ejemplo siguiente se registra la variable de entorno :

  • JavaScript
  • TypeScript
module.exports = async function (context) {
  context.log(`WEBSITE_SITE_NAME: ${process.env["WEBSITE_SITE_NAME"]}`);
};
  • JavaScript
  • TypeScript
async function timerTrigger1(myTimer, context) {
  context.log(`WEBSITE_SITE_NAME: ${process.env["WEBSITE_SITE_NAME"]}`);
}

Entorno de desarrollo local

Cuando se ejecute a nivel local, el proyecto de funciones incluirá un archivo, donde se almacenarán las variables de entorno en el objeto .

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "",
    "FUNCTIONS_WORKER_RUNTIME": "node",
    "CUSTOM_ENV_VAR_1": "hello",
    "CUSTOM_ENV_VAR_2": "world"
  }
}

En el entorno de nube de Azure

Cuando se ejecuta en Azure, la aplicación de funciones le permite establecer y usar Configuración de aplicaciones, como cadenas de conexión de servicio, y expone esta configuración como variables de entorno durante la ejecución.

Hay varias maneras de agregar, actualizar y eliminar opciones de configuración de la aplicación de función:

Para aplicar los cambios realizados en la configuración de la aplicación de funciones, es necesario reiniciar la aplicación de funciones.

Variables de entorno de trabajo

Hay varias variables de entorno de Functions específicas de Node.js:

argumentos languageWorkers de nodo

Esta configuración permite especificar argumentos personalizados al iniciar el proceso de Node.js. Se suele usar localmente para iniciar el trabajo en modo de depuración, pero también se puede usar en Azure si necesita argumentos personalizados.

Advertencia

Si es posible, evite usar languageWorkers__node__arguments en Azure porque puede tener un impacto negativo en los tiempos de arranque en frío. En lugar de usar trabajos iniciados previamente, el tiempo de ejecución debe iniciar un nuevo trabajo desde cero con los argumentos personalizados.

registros de trabajo logLevel

Esta configuración ajusta el nivel de registro predeterminado para los registros de trabajo específicos de Node.js. De forma predeterminada, solo se muestran los registros de advertencias o errores, pero puede establecerla en o para ayudar a diagnosticar problemas con el trabajo de Node.js. Para más información, consulte Configuración de los niveles de registro.

Módulos ECMAScript (versión preliminar)

Nota:

Los módulos ECMAScript son actualmente una característica en vista previa en Node.js 14 y siguientes en Azure Functions.

Los módulos ECMAScript (módulos ES) son el nuevo sistema de módulos estándar oficial de Node.js. Hasta ahora, en los ejemplos de código de este artículo se usa la sintaxis CommonJS. Al ejecutar Azure Functions en Node.js 14 o superior, puede elegir escribir las funciones mediante la sintaxis de módulos ES.

Para usar los módulos ES en una función, cambie su nombre de archivo para usar una extensión . El siguiente archivo index.mjs es una función desencadenada por HTTP que usa la sintaxis de los módulos ES para importar la biblioteca y devolver un valor.

  • JavaScript
  • TypeScript
import { v4 as uuidv4 } from "uuid";

async function httpTrigger1(context, request) {
  context.res.body = uuidv4();
}

export default httpTrigger;
  • JavaScript
  • TypeScript
import { v4 as uuidv4 } from "uuid";

async function httpTrigger1(request, context) {
  return { body: uuidv4() };
}

app.http("httpTrigger1", {
  methods: ["GET", "POST"],
  handler: httpTrigger1,
});

Configuración del punto de entrada de la función

Las propiedades de y pueden usarse para configurar la ubicación y el nombre de la función exportada. La propiedad es necesaria cuando se usa TypeScript y se debe apuntar al JavaScript compilado.

Usar

De forma predeterminada, se ejecuta una función de JavaScript desde , un archivo que comparte el mismo directorio primario que su archivo correspondiente.

se puede usar para obtener una estructura de carpetas que tenga el aspecto del ejemplo siguiente:

<project_root>/
 | - node_modules/
 | - myFirstFunction/
 | | - function.json
 | - lib/
 | | - sayHello.js
 | - host.json
 | - package.json

para debe incluir una propiedad que señala al archivo con la función exportada que ejecutar.

{
  "scriptFile": "../lib/sayHello.js",
  "bindings": [
    ...
  ]
}

Usar

En el modelo v3, una función debe exportarse con para que se pueda encontrar y ejecutar. De forma predeterminada, la función que se ejecuta cuando se desencadena es la única exportación de ese archivo, la exportación denominada o la exportación denominada . El ejemplo siguiente establece en un valor personalizado, "logHello":

{
  "entryPoint": "logHello",
  "bindings": [
    ...
  ]
}
  • JavaScript
  • TypeScript
async function logHello(context) {
  context.log("Hello, world!");
}

module.exports = { logHello };

Depuración local

Se recomienda usar VS Code para la depuración local, que inicia el proceso de Node.js en modo de depuración automáticamente y se asocia al proceso automáticamente. Para obtener más información, consulte Ejecución local de la función.

Si usa una herramienta diferente para la depuración o quiere iniciar manualmente el proceso de Node.js en modo de depuración, agregue después de en local.settings.json. El argumento indica a Node.js que escuche un cliente de depuración, en el puerto 9229 de forma predeterminada. Para obtener más información, consulte la guía de depuración de Node.js.

Recomendaciones

En esta sección se describen varios patrones impactantes para aplicaciones de Node.js que recomendamos seguir.

Elección de los planes de App Service de una sola vCPU

Al crear una aplicación de función que usa el plan de App Service, se recomienda que seleccione un plan de una sola vCPU, en lugar de un plan con varias vCPU. En la actualidad, Functions ejecuta funciones de Node.js con más eficacia en VM con una sola vCPU. El uso de máquinas virtuales más grandes no producirá las mejoras de rendimiento esperadas. Cuando sea necesario, puede escalar horizontalmente de forma manual mediante la adición de más instancias de máquina virtual de una sola vCPU o bien puede habilitar el escalado automático. Para obtener más información, consulte Escalación del recuento de instancias de forma manual o automática.

Ejecución desde un archivo de paquete

Al desarrollar Azure Functions en el modelo de hospedaje sin servidor, los arranques en frío son una realidad. Arranque en frío hace referencia a la primera vez en que su aplicación de funciones se inicia después de un período de inactividad, tardando más tiempo en iniciarse. Especialmente para las aplicaciones de Node.js con árboles de dependencias de gran tamaño, el arranque en frío puede ser importante. Para acelerar el proceso de arranque en frío, ejecute sus funciones como un archivo de paquete cuando sea posible. Muchos métodos de implementación usan este modelo de forma predeterminada, pero si experimentase numerosos arranques en frío, debería hacer alguna comprobación para asegurarse de que se esté ejecutando de esta manera.

Uso de un único cliente estático

Cuando se usa un cliente específico del servicio en una aplicación de Azure Functions, no cree un nuevo cliente con cada invocación de función porque puede alcanzar los límites de conexión. En su lugar, cree un único cliente estático en el ámbito global. Para obtener más información, consulte administrar conexiones en Azure Functions.

Uso de y

Al escribir Azure Functions en Node.js, debe escribir código con las palabras clave async y await. El hecho de escribir el código con y en lugar de usar devoluciones de llamada o y con promesas ayuda a evitar dos problemas comunes:

  • El inicio de excepciones no detectadas que bloquean el proceso de Node.js, que puede afectar a la ejecución de otras funciones.
  • Comportamiento inesperado, como la ausencia de registros de debido a llamadas asincrónicas que no se esperan correctamente.

En el ejemplo siguiente, se invoca el método asincrónico con una función de devolución de llamada error-first como segundo parámetro. Este código provoca los dos problemas mencionados anteriormente. Una excepción no detectada explícitamente en el ámbito correcto puede bloquear todo el proceso (problema 1). Regresar sin asegurarse de que el callback termine significa que la respuesta HTTP a veces tiene un cuerpo vacío (ver problema n.º 2).

  • JavaScript
  • TypeScript
// DO NOT USE THIS CODE
const { app } = require('@azure/functions');
const fs = require('fs');

app.http('httpTriggerBadAsync', {
    methods: ['GET', 'POST'],
    authLevel: 'anonymous',
    handler: async (request, context) => {
        let fileData;
        fs.readFile('./helloWorld.txt', (err, data) => {
            if (err) {
                context.error(err);
                // BUG #1: This will result in an uncaught exception that crashes the entire process
                throw err;
            }
            fileData = data;
        });
        // BUG #2: fileData is not guaranteed to be set before the invocation ends
        return { body: fileData };
    },
});

En el ejemplo siguiente, se invoca el método asincrónico con una función de devolución de llamada error-first como segundo parámetro. Este código provoca los dos problemas mencionados anteriormente. Una excepción no detectada explícitamente en el ámbito correcto puede bloquear todo el proceso (problema 1). Llamar al método en desuso fuera del ámbito de la devolución de llamada puede indicar que la función ha terminado antes de que se lea el archivo (problema 2). En este ejemplo, una llamada a demasiado pronto provoca la ausencia de las entradas de registro que empiezan por .

  • JavaScript
  • TypeScript
// NOT RECOMMENDED PATTERN
const fs = require("fs");

module.exports = function (context) {
  fs.readFile("./hello.txt", (err, data) => {
    if (err) {
      context.log.error("ERROR", err);
      // BUG #1: This will result in an uncaught exception that crashes the entire process
      throw err;
    }
    context.log(`Data from file: ${data}`);
    // context.done() should be called here
  });
  // BUG #2: Data is not guaranteed to be read before the Azure Function's invocation ends
  context.done();
};

Use las palabras clave y para ayudar a evitar ambos problemas. La mayoría de las API del ecosistema de Node.js se han convertido para admitir promesas de alguna forma. Por ejemplo, a partir de la versión 14, Node.js proporciona una API para reemplazar la API de devolución de llamada .

En el ejemplo siguiente, las excepciones no controladas iniciadas durante la ejecución de la función solo devolverán un error para la invocación individual que generó una excepción. La palabra clave significa que los pasos después de solo se ejecutarán una vez finalizado.

  • JavaScript
  • TypeScript
// Recommended pattern
const { app } = require('@azure/functions');
const fs = require('fs/promises');

app.http('httpTriggerGoodAsync', {
    methods: ['GET', 'POST'],
    authLevel: 'anonymous',
    handler: async (request, context) => {
        try {
            const fileData = await fs.readFile('./helloWorld.txt');
            return { body: fileData };
        } catch (err) {
            context.error(err);
            // This rethrown exception will only fail the individual invocation, instead of crashing the whole process
            throw err;
        }
    },
});

Con y , tampoco es necesario llamar a la devolución de llamada .

  • JavaScript
  • TypeScript
// Recommended pattern
const fs = require("fs/promises");

module.exports = async function (context) {
  let data;
  try {
    data = await fs.readFile("./hello.txt");
  } catch (err) {
    context.log.error("ERROR", err);
    // This rethrown exception will be handled by the Functions Runtime and will only fail the individual invocation
    throw err;
  }
  context.log(`Data from file: ${data}`);
};

Solución de problemas

Consulte la guía de solución de problemas de Node.js.

Pasos siguientes

Para obtener más información, consulte los siguientes recursos: