Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Este guia é uma introdução ao desenvolvimento de Azure Functions usando JavaScript ou TypeScript. O artigo assume que já leu o guia para desenvolvedores Azure Functions.
Importante
O conteúdo deste artigo muda com base na sua escolha do modelo de programação Node.js no seletor na parte superior desta página. A versão escolhida deve corresponder à versão do @azure/functions pacote npm que você está usando em seu aplicativo. Caso não tenhas esse pacote listado no package.json, o padrão será v3. Saiba mais sobre as diferenças entre v3 e v4 no guia de migração.
Como desenvolvedor Node.js, você também pode estar interessado em um dos seguintes artigos:
| Primeiros Passos | Conceitos | Aprendizagem orientada |
|---|---|---|
Considerações
- O modelo de programação Node.js não deve ser confundido com o tempo de execução Azure Functions:
- Modelo de programação: define como você cria seu código e é específico para JavaScript e TypeScript.
- Runtime: Define o comportamento subjacente do Azure Functions e é partilhado entre todas as linguagens.
- A versão do modelo de programação está estritamente ligada à versão do
@azure/functionspacote npm. É versionado independentemente do tempo de execução. Tanto o tempo de execução quanto o modelo de programação usam o número 4 como sua última versão principal, mas isso é uma coincidência. - Não é possível misturar os modelos de programação v3 e v4 no mesmo aplicativo de função. Assim que você registrar uma função v4 em seu aplicativo, todas as funções v3 registradas em arquivos function.json serão ignoradas.
Versões suportadas
A tabela seguinte mostra cada versão do modelo de programação Node.js juntamente com as suas versões suportadas do tempo de execução Azure Functions e Node.js.
| Versão do modelo de programação | Nível de Suporte | Versão do Functions Runtime | Versão Node.js | Descrição |
|---|---|---|---|---|
| 4.x | disponibilidade geral | 4.25+ | 22,x 20,x, 18,x | Suporta uma estrutura de arquivos flexível e uma abordagem centrada em código para gatilhos e associações. |
| 3.x | disponibilidade geral | 4.x | 20,x, 18,x, 16,x, 14,x | Requer uma estrutura de arquivo específica com seus gatilhos e ligações declarados em um arquivo "function.json" |
| 2.x | n/d | 3.x | 14,x, 12,x, 10,x | Chegou ao fim do suporte em 13 de dezembro de 2022. Consulte Versões de funções para obter mais informações. |
| 1.x | n/d | 2.x | 10,x, 8,x | Chegou ao fim do suporte em 13 de dezembro de 2022. Consulte Versões de funções para obter mais informações. |
Estrutura de pastas
A estrutura de pastas necessária para um projeto JavaScript se parece com o exemplo a seguir:
<project_root>/
| - .vscode/
| - node_modules/
| - myFirstFunction/
| | - index.js
| | - function.json
| - mySecondFunction/
| | - index.js
| | - function.json
| - .funcignore
| - host.json
| - local.settings.json
| - package.json
A pasta principal do projeto, <project_root>, pode conter os seguintes arquivos:
- .vscode/: (Opcional) Contém a configuração Visual Studio Code armazenada. Para saber mais, consulte Visual Studio Code definições.
- myFirstFunction/function.json: Contém a configuração para o gatilho, entradas e saídas da função. O nome do diretório determina o nome da sua função.
- myFirstFunction/index.js: Armazena seu código de função. Para alterar esse caminho de arquivo padrão, consulte usando scriptFile.
- .funcignore: (Opcional) Declara ficheiros que não deveriam ser publicados em Azure. Normalmente, esse arquivo contém .vscode/ para ignorar a configuração do editor, testar/ ignorar casos de teste e local.settings.json para impedir que as configurações do aplicativo local sejam publicadas.
- host.json: Contém opções de configuração que afetam todas as funções em uma instância de aplicativo de função. Este ficheiro é publicado no Azure. Nem todas as opções são suportadas quando executadas localmente. Para saber mais, consulte host.json.
- local.settings.json: Usado para armazenar configurações de aplicativos e cadeias de conexão quando ele está sendo executado localmente. Este ficheiro não é publicado no Azure. Para saber mais, consulte local.settings.file.
- package.json: Contém opções de configuração como uma lista de dependências de pacote, o ponto de entrada principal e scripts.
A estrutura de pastas recomendada para um projeto JavaScript se parece com o exemplo a seguir:
<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
A pasta principal do projeto, <project_root>, pode conter os seguintes arquivos:
- .vscode/: (Opcional) Contém a configuração Visual Studio Code armazenada. Para saber mais, consulte Visual Studio Code definições.
- src/functions/: O local padrão para todas as funções e seus gatilhos e ligações relacionados.
- test/: (Opcional) Contém os casos de teste do seu aplicativo de função.
- .funcignore: (Opcional) Declara ficheiros que não deveriam ser publicados em Azure. Normalmente, esse arquivo contém .vscode/ para ignorar a configuração do editor, testar/ ignorar casos de teste e local.settings.json para impedir que as configurações do aplicativo local sejam publicadas.
- host.json: Contém opções de configuração que afetam todas as funções em uma instância de aplicativo de função. Este ficheiro é publicado no Azure. Nem todas as opções são suportadas quando executadas localmente. Para saber mais, consulte host.json.
- local.settings.json: Usado para armazenar configurações de aplicativos e cadeias de conexão quando ele está sendo executado localmente. Este ficheiro não é publicado no Azure. Para saber mais, consulte local.settings.file.
- package.json: Contém opções de configuração como uma lista de dependências de pacote, o ponto de entrada principal e scripts.
Registar uma função
O modelo v3 registra uma função baseada na existência de dois arquivos. Primeiro, você precisa de um function.json arquivo localizado em uma pasta um nível abaixo da raiz do seu aplicativo. Em segundo lugar, você precisa de um arquivo JavaScript que exporte sua função. Por padrão, o modelo procura um arquivo index.js na mesma pasta que o function.json. Se estiveres a usar TypeScript, deves usar a propriedade scriptFile em function.json para apontar para o ficheiro JavaScript compilado. Para personalizar o local do arquivo ou o nome de exportação da sua função, consulte configurando o ponto de entrada da sua função.
A função exportada deve ser sempre declarada como uma async function no modelo v3. Você pode exportar uma função síncrona, mas então deve chamar context.done() para sinalizar que a sua função está concluída, algo que está desaconselhado e não recomendado.
Sua função recebe uma invocação context como o primeiro argumento e suas entradas como os argumentos restantes.
O exemplo a seguir é uma função simples que registra que ela foi acionada e responde com Hello, world!:
{
"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!" };
};
O modelo de programação carrega suas funções com base no main campo em seu package.json. Você pode definir o main campo como um único arquivo ou vários arquivos usando um padrão glob. A tabela a seguir mostra valores de exemplo para o main campo:
| Exemplo | Descrição |
|---|---|
src/index.js |
Registre funções a partir de um único arquivo raiz. |
src/functions/*.js |
Registe cada função a partir do seu próprio ficheiro. |
src/{index.js,functions/*.js} |
Uma combinação em que você registra cada função de seu próprio arquivo, mas ainda tem um arquivo raiz para código geral no nível do aplicativo. |
Para registrar uma função, você deve importar o app objeto do @azure/functions módulo npm e chamar o método específico para seu tipo de gatilho. O primeiro argumento ao registrar uma função é o nome da função. O segundo argumento é um options objeto que especifica a configuração para seu gatilho, seu manipulador e quaisquer outras entradas ou saídas. Em alguns casos, quando a configuração do gatilho não é necessária, pode-se passar o manipulador diretamente como segundo argumento em vez de um objeto options.
O registo de uma função pode ser feito a partir de qualquer ficheiro no seu projeto, desde que esse ficheiro seja carregado (direta ou indiretamente) com base no main campo no seu package.json ficheiro. A função deve ser registrada em um escopo global porque você não pode registrar funções depois que as execuções começam.
O exemplo a seguir é uma função simples que registra que ela foi acionada e responde com Hello, world!:
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 e saídas
A sua função deve ter exatamente um input primário chamado gatilho. Também pode ter entradas e/ou saídas secundárias. As entradas e saídas são configuradas em seus function.json arquivos e também são chamadas de associações.
Entradas
As entradas são ligações com direction definido como in. A principal diferença entre um gatilho e uma entrada secundária é que um gatilho type termina em Trigger. Por exemplo, tipo blobTrigger vs tipo blob. A maioria das funções usa apenas um gatilho e não há suporte para muitos tipos de entrada secundária.
As entradas podem ser acessadas de várias maneiras:
[Recomendado] Como argumentos passados para sua função: use os argumentos na mesma ordem em que são definidos em
function.json. Anamepropriedade definida emfunction.jsonnão precisa corresponder ao nome do seu argumento, embora a recomendemos por uma questão de organização.module.exports = async function (context, myTrigger, myInput, myOtherInput) { ... };
Como propriedades de
context.bindings: Use a chave correspondente ànamepropriedade definida emfunction.json.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); };
Saídas
As saídas são associações com direction definidas para out e podem ser configuradas de várias maneiras:
[Recomendado para saída única] Retornar o valor diretamente: se você estiver usando uma função assíncrona, poderá retornar o valor diretamente. Você deve alterar a
namepropriedade da ligação de saída para$returnemfunction.jsoncomo no exemplo a seguir:{ "name": "$return", "type": "http", "direction": "out" }module.exports = async function (context, request) { return { body: "Hello, world!", }; };
[Recomendado para várias saídas] Retorne um objeto contendo todas as saídas: se estiveres a usar uma função assíncrona, poderás retornar um objeto com uma propriedade correspondente ao nome de cada vinculação no
function.json. O exemplo a seguir usa ligações de saída chamadas "httpResponse" e "queueOutput":{ "name": "httpResponse", "type": "http", "direction": "out" }, { "name": "queueOutput", "type": "queue", "direction": "out", "queueName": "helloworldqueue", "connection": "storage_APPSETTING" }module.exports = async function (context, request) { let message = "Hello, world!"; return { httpResponse: { body: message, }, queueOutput: message, }; };
Definir valores em
context.bindings: Se você não estiver usando uma função assíncrona ou não quiser usar as opções anteriores, poderá definir valores diretamente nocontext.bindings, onde a chave corresponde ao nome da ligação. O exemplo a seguir usa ligações de saída chamadas "httpResponse" e "queueOutput":{ "name": "httpResponse", "type": "http", "direction": "out" }, { "name": "queueOutput", "type": "queue", "direction": "out", "queueName": "helloworldqueue", "connection": "storage_APPSETTING" }module.exports = async function (context, request) { let message = "Hello, world!"; context.bindings.httpResponse = { body: message, }; context.bindings.queueOutput = message; };
Tipo de dados de vinculações
Você pode usar a dataType propriedade em uma associação de entrada para alterar o tipo de sua entrada. No entanto, a abordagem tem algumas limitações:
- No Node.js, apenas
stringebinarysão suportados (streamnão é) - Para entradas HTTP, a
dataTypepropriedade é ignorada. Em vez disso, use propriedades no objetorequestpara obter o corpo no formato desejado. Para obter mais informações, consulte Solicitação HTTP.
No exemplo a seguir de um gatilho de fila de armazenamento, o tipo padrão de myQueueItem é um string, mas se você definir dataType como binary, o tipo mudará para um Node.js Buffer.
{
"name": "myQueueItem",
"type": "queueTrigger",
"direction": "in",
"queueName": "helloworldqueue",
"connection": "storage_APPSETTING",
"dataType": "binary"
}
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");
}
};
A sua função deve ter exatamente um input primário chamado gatilho. Também pode ter entradas secundárias, uma saída primária chamada saída de retorno e/ou saídas secundárias. As entradas e saídas também são referidas como ligações fora do contexto do modelo de programação Node.js. Antes da v4 do modelo, essas ligações eram configuradas em function.json arquivos.
Entrada de gatilho
O gatilho é a única entrada ou saída necessária. Para a app maioria dos tipos de gatilho, você registra uma função usando um método no objeto nomeado após o tipo de gatilho. Você pode especificar a configuração específica para o gatilho diretamente no options argumento. Por exemplo, um gatilho HTTP permite especificar uma rota. Durante a execução, o valor correspondente a esse gatilho é passado como o primeiro argumento para o manipulador.
const { app } = require('@azure/functions');
app.http('helloWorld1', {
route: 'hello/world',
handler: async (request, context) => {
...
}
});
Resultado de saída
A saída de retorno é opcional e, em alguns casos, configurada por padrão. Por exemplo, um gatilho HTTP registrado com app.http é configurado para retornar uma saída de resposta HTTP automaticamente. Para a maioria dos tipos de saída, especifica-se no argumento a options configuração de retorno com a ajuda do objeto output exportado do módulo @azure/functions. Durante a execução, você define essa saída retornando-a do manipulador.
O exemplo a seguir usa um gatilho de temporizador e uma saída de fila de armazenamento:
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 e saídas extras
Além do gatilho e do retorno, você pode especificar entradas ou saídas extras no options argumento ao registrar uma função. Os objetos input e output exportados do módulo @azure/functions fornecem métodos específicos do tipo para ajudar a construir a configuração. Durante a execução, você obtém ou define os valores com context.extraInputs.get ou context.extraOutputs.set, passando o objeto de configuração original como o primeiro argumento.
O exemplo a seguir é uma função acionada por uma fila de armazenamento, com uma entrada de blob de armazenamento extra que é copiada para uma saída de blob de armazenamento extra. A mensagem de fila deve ser o nome de um ficheiro e substitui {queueTrigger} como o nome de blob a ser copiado, com a ajuda de uma expressão de associação.
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 e saídas genéricas
Os objetos app, trigger, input e output exportados pelo módulo @azure/functions fornecem métodos específicos de tipo para a maioria dos tipos. Para todos os tipos que não são suportados, um generic método é fornecido para permitir que você especifique manualmente a configuração. O generic método também pode ser usado se você quiser alterar as configurações padrão fornecidas por um método específico do tipo.
O exemplo seguinte é uma função simples acionada por HTTP que utiliza métodos genéricos em substituição a métodos específicos de tipo.
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
Várias extensões de binding permitem agora trabalhar diretamente com os tipos de Azure SDK.
Armazenamento em Blobs do Azure
A capacidade de ligações SDK no Azure Functions permite trabalhar diretamente com os tipos do SDK de armazenamento de blobs do Azure como BlobClient e ContainerClient em vez de dados brutos. Isso fornece acesso total a todos os métodos SDK ao trabalhar com blobs.
Para configurar o seu projeto para funcionar com tipos de SDK:
- Adicione os
@azure/functions-extensions-blobpacotes de pré-visualização de extensões aopackage.jsonficheiro do projeto, que devem incluir pelo menos estes pacotes:
"dependencies": {
"@azure/functions": "4.7.2-preview",
"@azure/functions-extensions-blob": "0.2.0-preview"
},
- Adicione
enableHttpStream: trueao seuapp.setuppara suportar tipos de streaming:
import { app } from '@azure/functions';
app.setup({
enableHttpStream: true,
});
Este exemplo mostra como obter o BlobClient de um desencadeador de Blob de Armazenamento e da ligação de entrada de um desencadeador 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,
});
Este exemplo mostra como obter o ContainerClient de uma ligação de entrada de Storage Blob utilizando um gatilho 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,
});
Tenha estas considerações em mente ao trabalhar com tipos de SDK:
- Mantenha
import "@azure/functions-extensions-blob"sempre em primeiro lugar nos seus ficheiros para garantir que os efeitos colaterais ocorram. - Defina
sdkBinding: truena configuração de ligação. - Use o tipo de cliente apropriado para a sua operação:
-
blobClientpara operações sobre um único blob -
containerClientpara operações num contentor
-
- Lidar de forma adequada com erros usando blocos
try/catch - Para operações de grandes blobs, considere usar métodos de streaming para evitar problemas de memória.
Para mais informações, consulte estes Blob Storage SDK Bindings for Node.js Samples: para mais exemplos sobre como incorporar SDK Bindings for Blob na sua aplicação de funções.
Azure Service Bus
Este exemplo utiliza o tipo SDK ServiceBusReceivedMessage obtido a partir de ServiceBusMessageContext fornecido pelo gatilho 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 outro exemplo de utilização de tipos SDK, veja a amostra de estratégia de recuo exponencial .
Contexto de invocação
Cada invocação de sua função recebe um objeto de invocação context , usado para ler entradas, definir saídas, gravar em logs e ler vários metadados. No modelo v3, o objeto de contexto é sempre o primeiro argumento passado para o manipulador.
O context objeto tem as seguintes propriedades:
| Propriedade | Descrição |
|---|---|
invocationId |
A ID da invocação da função atual. |
executionContext |
Consulte o contexto de execução. |
bindings |
Consulte as ligações. |
bindingData |
Metadados sobre a entrada de gatilho para essa invocação, não incluindo o valor em si. Por exemplo, um gatilho de hub de eventos tem uma enqueuedTimeUtc propriedade. |
traceContext |
O contexto para o rastreamento distribuído. Para obter mais informações, veja Trace Context. |
bindingDefinitions |
A configuração de suas entradas e saídas, conforme definido em function.json. |
req |
Consulte Solicitação HTTP. |
res |
Consulte a resposta HTTP. |
context.executionContext
O context.executionContext objeto tem as seguintes propriedades:
| Propriedade | Descrição |
|---|---|
invocationId |
A ID da invocação da função atual. |
functionName |
O nome da função que está sendo invocada. O nome da pasta que contém o function.json arquivo determina o nome da função. |
functionDirectory |
A pasta que contém o function.json arquivo. |
retryContext |
Consulte o contexto de repetição. |
context.executionContext.retryContext
O context.executionContext.retryContext objeto tem as seguintes propriedades:
| Propriedade | Descrição |
|---|---|
retryCount |
Um número que representa a tentativa atual de novo envio. |
maxRetryCount |
Número máximo de vezes que uma execução é repetida. Um valor de -1 significa repetir tentativas indefinidamente. |
exception |
Exceção que causou a nova tentativa. |
context.bindings
O context.bindings objeto é usado para ler entradas ou definir saídas. O exemplo a seguir é um gatilho de fila de armazenamento, que usa context.bindings para copiar uma entrada de blob de armazenamento para uma saída de blob de armazenamento. O conteúdo da mensagem de fila substitui {queueTrigger} para ser o nome do ficheiro a ser copiado, com a ajuda de uma expressão de associação.
{
"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"
}
module.exports = async function (context, myQueueItem) {
const blobValue = context.bindings.myInput;
context.bindings.myOutput = blobValue;
};
contexto.concluído
O context.done método foi preterido. Antes de as funções assíncronas serem suportadas, você sinalizaria que sua função é feita chamando context.done():
module.exports = function (context, request) {
context.log("this pattern is now deprecated");
context.done();
};
Recomendamos que você remova a chamada para context.done() e marque sua função como assíncrona (async) para que ela retorne uma promessa (promise) (mesmo que você não await faça nada). Assim que sua função termina (em outras palavras, a promessa retornada é resolvida), o modelo v3 sabe que sua função está concluída.
module.exports = async function (context, request) {
context.log("you don't need context.done or an awaited call");
};
Cada invocação de sua função é passada um objeto de invocação context , com informações sobre sua invocação e métodos usados para registro. No modelo v4, o context objeto é normalmente o segundo argumento passado para o manipulador.
A InvocationContext classe tem as seguintes propriedades:
| Propriedade | Descrição |
|---|---|
invocationId |
A ID da invocação da função atual. |
functionName |
O nome da função. |
extraInputs |
É utilizado para obter os valores das entradas adicionais. Para obter mais informações, consulte entradas e saídas extras. |
extraOutputs |
Usado para definir os valores de saídas extras. Para obter mais informações, consulte entradas e saídas extras. |
retryContext |
Consulte o contexto de repetição. |
traceContext |
O contexto para o rastreamento distribuído. Para obter mais informações, veja Trace Context. |
triggerMetadata |
Metadados sobre a entrada de gatilho para essa invocação, não incluindo o valor em si. Por exemplo, um gatilho de hub de eventos tem uma enqueuedTimeUtc propriedade. |
options |
As opções usadas ao registrar a função, depois de validadas e com os padrões explicitamente especificados. |
Contexto de tentativa de repetição
O retryContext objeto tem as seguintes propriedades:
| Propriedade | Descrição |
|---|---|
retryCount |
Um número que representa a tentativa atual de novo envio. |
maxRetryCount |
Número máximo de vezes que uma execução é repetida. Um valor de -1 significa repetir tentativas indefinidamente. |
exception |
Exceção que causou a nova tentativa. |
Para obter mais informações, veja retry-policies.
Registo
Em Azure Functions, recomenda-se usar context.log() para escrever registos. O Azure Functions integra-se com o Azure Application Insights para capturar melhor os registos da sua aplicação de funções. O Application Insights, parte do Azure Monitor, fornece funcionalidades para recolha, renderização visual e análise tanto dos registos de aplicação como das saídas dos seus traços. Para saber mais, consulte monitorização Azure Functions.
Nota
Se você usar o método Node.js console.log alternativo, esses logs serão rastreados no nível do aplicativo e não serão associados a nenhuma função específica. É altamente recomendável o uso de context para registo em vez de console para que todos os registos sejam associados a uma função específica.
O exemplo a seguir grava um log no nível "information" padrão, incluindo a ID de invocação:
context.log(`Something has happened. Invocation ID: "${context.invocationId}"`);
Níveis de log
Além do método padrão context.log , os seguintes métodos estão disponíveis que permitem gravar logs em níveis específicos:
| Método | Descrição |
|---|---|
context.log.error() |
Grava um evento de nível de erro nos logs. |
context.log.warn() |
Grava um evento de nível de aviso nos logs. |
context.log.info() |
Grava um evento de nível de informação nos logs. |
context.log.verbose() |
Grava um evento de nível de rastreamento nos logs. |
| Método | Descrição |
|---|---|
context.trace() |
Grava um evento de nível de rastreamento nos logs. |
context.debug() |
Grava um evento de nível de depuração nos logs. |
context.info() |
Grava um evento de nível de informação nos logs. |
context.warn() |
Grava um evento de nível de aviso nos logs. |
context.error() |
Grava um evento de nível de erro nos logs. |
Configurar nível de log
O Azure Functions permite-lhe definir o nível de limiar a ser usado ao rastrear e visualizar registos. Para definir o limite, use a propriedade logging.logLevel no arquivo host.json. Essa propriedade permite definir um nível padrão aplicado a todas as funções ou um limite para cada função individual. Para saber mais, consulte Como configurar a monitorização para Azure Functions.
Monitorizar dados personalizados
Por defeito, o Azure Functions escreve a saída como registos no Application Insights. Para maior controlo, pode usar o SDK do Application Insights Node.js para enviar logs personalizados, métricas e dependências para a sua instância do Application Insights.
Nota
Os métodos no Application Insights Node.js SDK podem mudar ao longo do tempo. Podem existir pequenas diferenças de sintaxe em relação aos exemplos aqui apresentados. Para os exemplos mais recentes de utilização de APIs, consulte a documentação do Application Insights Node.js SDK.
Para rastreamento distribuído no modelo de programação Node.js v4, pode usar o @azure/functions-opentelemetry-instrumentation pacote em vez do Application Insights SDK. Este pacote fornece instrumentação automática baseada em OpenTelemetry para Azure Functions. Para mais informações, consulte o repositório OpenTelemetry Azure Functions Instrumentation para Node.js GitHub.
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,
});
};
O tagOverrides parâmetro define o ID de invocação da operation_Id função. Essa configuração permite correlacionar todos os logs personalizados e gerados automaticamente para uma determinada chamada de função.
Gatilhos HTTP
Os gatilhos HTTP e webhook usam objetos de solicitação e resposta para representar mensagens HTTP.
HTTP e webhook disparam o uso de HttpRequest e HttpResponse objetos para representar mensagens HTTP. As classes representam um subconjunto do padrão fetch, utilizando o undici pacote do Node.js.
Solicitação HTTP
O pedido pode ser acedido de várias formas:
Como segundo argumento para a sua função:
module.exports = async function (context, request) { context.log(`Http function processed request for url "${request.url}"`);
Da
context.reqpropriedade:module.exports = async function (context, request) { context.log(`Http function processed request for url "${context.req.url}"`);
A partir das ligações de entrada nomeadas: Esta opção funciona da mesma forma que qualquer ligação não HTTP. O nome da associação em
function.jsondeve corresponder à chave emcontext.bindings, ou "request1" no exemplo a seguir:{ "name": "request1", "type": "httpTrigger", "direction": "in", "authLevel": "anonymous", "methods": ["get", "post"] }module.exports = async function (context, request) { context.log(`Http function processed request for url "${context.bindings.request1.url}"`);
O HttpRequest objeto tem as seguintes propriedades:
| Propriedade | Tipo | Descrição |
|---|---|---|
method |
string |
Método de solicitação HTTP usado para invocar essa função. |
url |
string |
URL da solicitação. |
headers |
Record<string, string> |
Cabeçalhos de solicitação HTTP. Este objeto diferencia maiúsculas de minúsculas. Recomenda-se usar request.getHeader('header-name') em vez disso, que é insensível a maiúsculas e minúsculas. |
query |
Record<string, string> |
Consultar chaves e valores de parâmetros de cadeia de caracteres da URL. |
params |
Record<string, string> |
Chaves e valores de parâmetros de rota. |
user |
HttpRequestUser \| null |
Objeto que representa o usuário conectado, seja por meio da autenticação de funções, autenticação SWA ou nulo quando nenhum usuário estiver conectado. |
body |
Buffer \| string \| any |
Se o tipo de mídia for "application/octet-stream" ou "multipart/*", body é um Buffer. Se o valor for uma cadeia de caracteres passível de análise JSON, body será o objeto analisado. Caso contrário, body é uma cadeia de caracteres. |
rawBody |
string |
O corpo como uma corda. Apesar do nome, essa propriedade não retorna um Buffer. |
bufferBody |
Buffer |
O corpo como um tampão. |
A solicitação pode ser acessada como o primeiro argumento para seu manipulador para uma função acionada por HTTP.
async (request, context) => {
context.log(`Http function processed request for url "${request.url}"`);
O HttpRequest objeto tem as seguintes propriedades:
| Propriedade | Tipo | Descrição |
|---|---|---|
method |
string |
Método de solicitação HTTP usado para invocar essa função. |
url |
string |
URL da solicitação. |
headers |
Headers |
Cabeçalhos de solicitação HTTP. |
query |
URLSearchParams |
Consultar chaves e valores de parâmetros de cadeia de caracteres da URL. |
params |
Record<string, string> |
Chaves e valores de parâmetros de rota. |
user |
HttpRequestUser \| null |
Objeto que representa o usuário conectado, seja por meio da autenticação de funções, autenticação SWA ou nulo quando nenhum usuário estiver conectado. |
body |
ReadableStream \| null |
Corpo como um fluxo legível. |
bodyUsed |
boolean |
Um valor booleano que indica se o corpo já foi lido. |
Para aceder ao corpo de um pedido ou resposta, podem ser utilizados os seguintes métodos:
| Método | Tipo de Retorno |
|---|---|
arrayBuffer() |
Promise<ArrayBuffer> |
blob() |
Promise<Blob> |
formData() |
Promise<FormData> |
json() |
Promise<unknown> |
text() |
Promise<string> |
Nota
As funções do corpo podem ser executadas apenas uma vez. As chamadas subsequentes são resolvidas com strings ou ArrayBuffers vazias.
Resposta HTTP
A resposta pode ser definida de várias maneiras:
Defina a
context.respropriedade:module.exports = async function (context, request) { context.res = { body: `Hello, world!` };
Retornar a resposta: Se a função estiver assíncrona e você definir o nome da vinculação como
$returnnofunction.json, poderá retornar a resposta diretamente em vez de defini-la nocontext.{ "type": "http", "direction": "out", "name": "$return" }module.exports = async function (context, request) { return { body: `Hello, world!` };
Definir a ligação de saída nomeada: esta opção funciona da mesma forma que qualquer ligação não HTTP. O nome da associação em
function.jsondeve corresponder à chave emcontext.bindings, ou "response1" no exemplo a seguir:{ "type": "http", "direction": "out", "name": "response1" }module.exports = async function (context, request) { context.bindings.response1 = { body: `Hello, world!` };
Chamada
context.res.send(): Esta opção está obsoleta. Ele chamacontext.done()implicitamente e não pode ser usado em uma função assíncrona.module.exports = function (context, request) { context.res.send(`Hello, world!`);
Se você criar um novo objeto ao definir a resposta, esse objeto deverá corresponder à HttpResponseSimple interface, que tem as seguintes propriedades:
| Propriedade | Tipo | Descrição |
|---|---|---|
headers |
Record<string, string> (opcional) |
Cabeçalhos de resposta HTTP. |
cookies |
Cookie[] (opcional) |
Cookies de resposta HTTP. |
body |
any (opcional) |
Corpo de resposta HTTP. |
statusCode |
number (opcional) |
Código de status da resposta HTTP. Se não estiver definido, o padrão será 200. |
status |
number (opcional) |
O mesmo que statusCode. Esta propriedade será ignorada se statusCode estiver definida. |
Você também pode modificar o context.res objeto sem substituí-lo. O objeto padrão context.res usa a HttpResponseFull interface, que suporta os seguintes métodos, além das HttpResponseSimple propriedades:
| Método | Descrição |
|---|---|
status() |
Define o estado. |
setHeader() |
Configura um campo de cabeçalho. NOTA: res.set() e res.header() também são suportados e fazem a mesma coisa. |
getHeader() |
Obtenha um campo de cabeçalho. NOTA: res.get() também é suportado e faz a mesma coisa. |
removeHeader() |
Remove um cabeçalho. |
type() |
Define o cabeçalho "content-type". |
send() |
Este método foi preterido. Ele define o corpo e as chamadas context.done() para indicar que uma função de sincronização foi concluída. NOTA: res.end() também é suportado e faz a mesma coisa. |
sendStatus() |
Este método foi preterido. Ele define o código de status e as chamadas context.done() para indicar que uma função de sincronização foi concluída. |
json() |
Este método foi preterido. Ele define o "content-type" como "application/json", define o corpo e chama context.done() para indicar que uma função de sincronização foi concluída. |
A resposta pode ser definida de várias maneiras:
Como uma interface simples com o tipo
HttpResponseInit: Esta opção é a maneira mais concisa de retornar respostas.return { body: `Hello, world!` };
A HttpResponseInit interface tem as seguintes propriedades:
| Propriedade | Tipo | Descrição |
|---|---|---|
body |
BodyInit (opcional) |
Corpo de resposta HTTP como um dos ArrayBuffer, , , AsyncIterable<Uint8Array>, Blob, FormDataIterable<Uint8Array>, NodeJS.ArrayBufferViewURLSearchParams, , ou nullstring. |
jsonBody |
any (opcional) |
Um corpo de resposta HTTP serializável por JSON. Se definido, a propriedade HttpResponseInit.body é ignorada em favor desta propriedade. |
status |
number (opcional) |
Código de status da resposta HTTP. Se não estiver definido, o padrão será 200. |
headers |
HeadersInit (opcional) |
Cabeçalhos de resposta HTTP. |
cookies |
Cookie[] (opcional) |
Cookies de resposta HTTP. |
Como uma classe com tipo
HttpResponse: Esta opção fornece métodos auxiliares para ler e modificar várias partes da resposta, como os cabeçalhos.const response = new HttpResponse({ body: `Hello, world!` }); response.headers.set("content-type", "application/json"); return response;
A HttpResponse classe aceita um opcional HttpResponseInit como um argumento para seu construtor e tem as seguintes propriedades:
| Propriedade | Tipo | Descrição |
|---|---|---|
status |
number |
Código de status da resposta HTTP. |
headers |
Headers |
Cabeçalhos de resposta HTTP. |
cookies |
Cookie[] |
Cookies de resposta HTTP. |
body |
ReadableStream | null |
Corpo como um fluxo legível. |
bodyUsed |
boolean |
Um booleano indicando se o corpo já foi lido. |
Fluxos HTTP
Os fluxos HTTP são um recurso que facilita o processamento de dados grandes, o streaming de respostas OpenAI, o fornecimento de conteúdo dinâmico e o suporte a outros cenários HTTP principais. Ele permite que você transmita solicitações e respostas de pontos de extremidade HTTP em seu aplicativo de função Node.js. Use fluxos HTTP em cenários em que seu aplicativo requer troca e interação em tempo real entre cliente e servidor por HTTP. Você também pode usar fluxos HTTP para obter o melhor desempenho e confiabilidade para seus aplicativos ao usar HTTP.
Importante
Os fluxos HTTP não são suportados no modelo v3.
Atualize para o modelo v4 para usar o recurso de streaming HTTP.
Os tipos HttpRequest e HttpResponse existentes no modelo de programação v4 já suportam diversas formas de lidar com o corpo da mensagem, incluindo como fluxo.
Pré-requisitos
- O
@azure/functionspacote npm versão 4.3.0 ou posterior. - Azure Functions runtime versão 4.28 ou posterior.
- Azure Functions Core Tools versão 4.0.5530 ou uma versão posterior, que contém a versão correta em tempo de execução.
Ativar fluxos
Use estes passos para ativar fluxos HTTP na sua aplicação de funções no Azure e nos seus projetos locais:
Se planeias transmitir grandes quantidades de dados, modifica a definição
FUNCTIONS_REQUEST_BODY_SIZE_LIMITno Azure. O tamanho máximo de corpo permitido padrão é104857600, o que limita suas solicitações a um tamanho de ~100 MB.Para o desenvolvimento local, adicione também
FUNCTIONS_REQUEST_BODY_SIZE_LIMITao arquivo local.settings.json.Adicione o seguinte código à sua aplicação em qualquer ficheiro incluído pelo campo principal.
const { app } = require("@azure/functions"); app.setup({ enableHttpStream: true });
Exemplos de fluxo
Este exemplo mostra uma função acionada por HTTP que recebe dados por meio de uma solicitação HTTP POST e a função transmite esses dados para um arquivo de saída especificado:
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!' };
},
});
Este exemplo mostra uma função acionada por HTTP que transmite o conteúdo de um arquivo como resposta a solicitações HTTP GET de entrada:
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 uma aplicação de exemplo pronta a executar usando streams, veja este exemplo em GitHub.
Considerações sobre o fluxo
- Use
request.bodypara obter o máximo benefício do uso de fluxos. Você ainda pode continuar a usar métodos comorequest.text(), que sempre retornam o corpo como uma string.
Ganchos
Ganchos não são suportados no modelo v3. Atualize para o modelo v4 para usar ganchos.
Use um gancho para executar código em diferentes pontos do ciclo de vida do Azure Functions. Os ganchos são executados na ordem em que são registrados e podem ser registrados a partir de qualquer arquivo em seu aplicativo. Atualmente, existem dois escopos de hooks: nível "app" e nível "invocação".
Ganchos de invocação
Os ganchos de invocação são executados uma vez por invocação da sua função, seja antes num gancho preInvocation ou depois num gancho postInvocation. Por padrão, a sua função é executada para todos os tipos de gatilhos, mas também pode filtrar por tipo. O exemplo a seguir mostra como registrar um gancho de invocação e filtrar por tipo de gatilho:
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}`
);
}
});
O primeiro argumento para o manipulador de gancho é um objeto de contexto específico para esse tipo de gancho.
O PreInvocationContext objeto tem as seguintes propriedades:
| Propriedade | Descrição |
|---|---|
inputs |
Os argumentos passaram para a invocação. |
functionHandler |
O manipulador de função para a invocação. As alterações nesse valor afetam a própria função. |
invocationContext |
O objeto de contexto de invocação passou para a função. |
hookData |
O local recomendado para armazenar e partilhar dados entre "hooks" (pontos de ancoragem) no mesmo âmbito. Você deve usar um nome de propriedade exclusivo para que ele não entre em conflito com os dados de outros hooks. |
O PostInvocationContext objeto tem as seguintes propriedades:
| Propriedade | Descrição |
|---|---|
inputs |
Os argumentos passaram para a invocação. |
result |
O resultado da função. As alterações a este valor afetam o resultado geral da função. |
error |
O erro gerado pela função, ou null/undefined se não houver nenhum erro. As alterações a este valor afetam o resultado geral da função. |
invocationContext |
O objeto de contexto de invocação passou para a função. |
hookData |
O local recomendado para armazenar e partilhar dados entre "hooks" (pontos de ancoragem) no mesmo âmbito. Você deve usar um nome de propriedade exclusivo para que ele não entre em conflito com os dados de outros hooks. |
Ganchos de aplicativo
Os hooks da aplicação são executados uma vez por instância da sua aplicação, tanto durante o arranque em um appStart hook quanto durante o encerramento em um appTerminate hook. Os ganchos de encerramento de aplicativo têm um tempo limitado para serem executados e não são executados em todos os cenários.
O runtime Azure Functions atualmente não suporta registo de contexto fora de uma invocação. Use o pacote npm do Application Insights para registrar dados durante ganchos no nível do aplicativo.
O exemplo a seguir registra hooks de aplicação:
const { app } = require('@azure/functions');
app.hook.appStart((context) => {
// add your logic here
});
app.hook.appTerminate((context) => {
// add your logic here
});
O primeiro argumento para o manipulador de gancho é um objeto de contexto específico para esse tipo de gancho.
O AppStartContext objeto tem as seguintes propriedades:
| Propriedade | Descrição |
|---|---|
hookData |
O local recomendado para armazenar e partilhar dados entre "hooks" (pontos de ancoragem) no mesmo âmbito. Você deve usar um nome de propriedade exclusivo para que ele não entre em conflito com os dados de outros hooks. |
O AppTerminateContext objeto tem as seguintes propriedades:
| Propriedade | Descrição |
|---|---|
hookData |
O local recomendado para armazenar e partilhar dados entre "hooks" (pontos de ancoragem) no mesmo âmbito. Você deve usar um nome de propriedade exclusivo para que ele não entre em conflito com os dados de outros hooks. |
Dimensionamento e simultaneidade
Por predefinição, o Azure Functions monitoriza automaticamente a carga da sua aplicação e cria mais instâncias de host para Node.js conforme necessário. O Azure Functions utiliza limiares incorporados (não configuráveis pelo utilizador) para diferentes tipos de triggers para decidir quando adicionar instâncias, como a idade das mensagens e o tamanho da fila para o QueueTrigger. Para obter mais informações, consulte Como funcionam os planos Consumo e Premium.
Esse comportamento de dimensionamento é suficiente para muitos aplicativos Node.js. Para aplicativos vinculados à CPU, você pode melhorar ainda mais o desempenho usando vários processos de trabalho de idioma. Você pode aumentar o número de processos de trabalho por host do padrão de 1 até um máximo de 10, usando a configuração de aplicativo FUNCTIONS_WORKER_PROCESS_COUNT. Azure Functions tenta então distribuir uniformemente as invocações simultâneas de funções entre estes trabalhadores. Esse comportamento torna menos provável que uma função com uso intensivo de CPU bloqueie a execução de outras funções. A definição aplica-se a cada host que o Azure Functions cria ao escalar a sua aplicação para responder à procura.
Aviso
Use a FUNCTIONS_WORKER_PROCESS_COUNT configuração com cuidado. Vários processos em execução na mesma instância podem levar a um comportamento imprevisível e aumentar os tempos de carregamento da função. Se você usar essa configuração, é altamente recomendável que você compense essas desvantagens executando a partir de um arquivo de pacote.
Versão do Node.js
Você pode ver a versão atual que o tempo de execução está a usar ao fazer logging de process.version a partir de qualquer função. Consulte supported versions para obter uma lista de Node.js versões suportadas por cada modelo de programação.
Definindo a versão do Node
A maneira como você atualiza sua versão Node.js depende do sistema operacional no qual seu aplicativo de função é executado.
Quando corre em Windows, a versão Node.js é definida pela definição WEBSITE_NODE_DEFAULT_VERSION da aplicação. Esta definição pode ser atualizada tanto usando a Azure CLI como no portal do Azure.
Para obter mais informações sobre Node.js versões, consulte Versões suportadas.
Antes de atualizares a versão Node.js, certifica-te de que a tua aplicação de funções está a correr na versão mais recente do tempo de execução Azure Functions. Se precisares de atualizar a tua versão de runtime, vê Migrar aplicações da versão Azure Functions 3.x para a versão 4.x.
Execute o comando Azure CLI az functionapp config appsettings set para atualizar a versão Node.js da sua aplicação de funções a correr no Windows:
az functionapp config appsettings set --settings WEBSITE_NODE_DEFAULT_VERSION=~22 \
--name <FUNCTION_APP_NAME> --resource-group <RESOURCE_GROUP_NAME>
Isso define a configuração da aplicação como a versão LTS suportada do WEBSITE_NODE_DEFAULT_VERSION.
Depois que as alterações forem feitas, seu aplicativo de função será reiniciado. Para saber mais sobre o suporte para Functions para Node.js, consulte a Política de suporte ao tempo de execução de linguagens.
Variáveis de ambiente
As variáveis de ambiente podem ser úteis para segredos operacionais (cadeias de conexão, chaves, pontos de extremidade, etc.) ou configurações ambientais, como variáveis de criação de perfil. Você pode adicionar variáveis de ambiente em seus ambientes locais e de nuvem e acessá-las através do process.env seu código de função.
O exemplo a seguir registra a WEBSITE_SITE_NAME variável de ambiente:
module.exports = async function (context) {
context.log(`WEBSITE_SITE_NAME: ${process.env["WEBSITE_SITE_NAME"]}`);
};
async function timerTrigger1(myTimer, context) {
context.log(`WEBSITE_SITE_NAME: ${process.env["WEBSITE_SITE_NAME"]}`);
}
Em ambiente de desenvolvimento local
Quando você executa localmente, seu projeto de funções inclui um local.settings.json arquivo, onde você armazena suas variáveis de Values ambiente no objeto.
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "",
"FUNCTIONS_WORKER_RUNTIME": "node",
"CUSTOM_ENV_VAR_1": "hello",
"CUSTOM_ENV_VAR_2": "world"
}
}
No ambiente cloud do Azure
Quando executas em Azure, a aplicação de funções permite-te definir e usar definições de aplicação, como cadeias de ligação de serviço, e expõe essas definições como variáveis de ambiente durante a execução.
Há várias maneiras de adicionar, atualizar e excluir as configurações do aplicativo de função:
As alterações nas configurações do aplicativo de função exigem que seu aplicativo de função seja reiniciado.
Variáveis do ambiente de trabalho
Existem várias variáveis de ambiente Functions específicas para Node.js:
argumentosdo nólanguageWorkers
Essa configuração permite especificar argumentos personalizados ao iniciar o processo de Node.js. É mais frequentemente usado localmente para iniciar o worker em modo de depuração, mas também pode ser usado no Azure se precisares de argumentos personalizados.
Aviso
Se possível, evite usar languageWorkers__node__arguments em Azure porque pode ter um efeito negativo nos tempos de arranque a frio. Ao invés de usar trabalhadores pré-aquecidos, o runtime tem que iniciar um novo trabalhador do zero com os seus argumentos personalizados.
RegistrologLevelWorker
Essa configuração ajusta o nível de log padrão para logs de trabalho específicos do Node.js. Por padrão, apenas os logs de aviso ou erro são mostrados, mas você pode defini-los para information ou debug para ajudar a diagnosticar problemas com o trabalhador Node.js. Para obter mais informações, consulte a configuração de níveis de log.
Módulos ECMAScript (pré-visualização)
Nota
Como os módulos ECMAScript são atualmente uma funcionalidade de versão de teste no Node.js 14 ou superior nas Azure Functions.
Os módulos ECMAScript (módulos ES) são o novo sistema de módulos padrão oficial para Node.js. Até agora, os exemplos de código neste artigo usam a sintaxe CommonJS. Ao executar Azure Functions em Node.js 14 ou superior, pode optar por escrever as suas funções usando a sintaxe dos módulos ES.
Para usar módulos ES em uma função, altere seu nome de arquivo para usar uma .mjs extensão. O exemplo de arquivo index.mjs a seguir é uma função acionada por HTTP que usa a sintaxe dos módulos ES para importar a uuid biblioteca e retornar um valor.
import { v4 as uuidv4 } from "uuid";
async function httpTrigger1(context, request) {
context.res.body = uuidv4();
}
export default httpTrigger;
import { v4 as uuidv4 } from "uuid";
async function httpTrigger1(request, context) {
return { body: uuidv4() };
}
app.http("httpTrigger1", {
methods: ["GET", "POST"],
handler: httpTrigger1,
});
Configurar ponto de entrada de função
As function.json propriedades scriptFile e entryPoint podem ser usadas para configurar o local e o nome da função exportada. A scriptFile propriedade é necessária quando você está usando TypeScript e deve apontar para o JavaScript compilado.
Ao utilizar scriptFile
Por padrão, uma função JavaScript é executada a partir de index.js, um arquivo que compartilha o mesmo diretório pai que seu diretório correspondente function.json.
scriptFile pode ser usado para obter uma estrutura de pastas semelhante ao exemplo a seguir:
<project_root>/
| - node_modules/
| - myFirstFunction/
| | - function.json
| - lib/
| | - sayHello.js
| - host.json
| - package.json
O function.json para myFirstFunction deve incluir uma propriedade scriptFile apontando para o ficheiro com a função exportada a ser executada.
{
"scriptFile": "../lib/sayHello.js",
"bindings": [
...
]
}
Ao utilizar entryPoint
No modelo v3, uma função deve ser exportada usando module.exports para ser encontrada e executada. Por padrão, a função que é executada quando acionada é a única exportação desse arquivo, a exportação nomeada runou a exportação nomeada index. O exemplo seguinte define o código entryPoint em function.json com um valor personalizado, "logHello":
{
"entryPoint": "logHello",
"bindings": [
...
]
}
async function logHello(context) {
context.log("Hello, world!");
}
module.exports = { logHello };
Depuração local
Recomendamos que utilize o VS Code para depuração local, que inicia automaticamente o seu processo de Node.js em modo de depuração e liga-se ao processo para si. Para obter mais informações, consulte Executar a função localmente.
Se você estiver usando uma ferramenta diferente para depuração ou quiser iniciar seu processo de Node.js no modo de depuração manualmente, adicione "languageWorkers__node__arguments": "--inspect" em Values seu local.settings.json. O argumento --inspect instrui o Node.js a ouvir um cliente de depuração, na porta 9229 por padrão. Para obter mais informações, consulte o guia de depuração do Node.js.
Recomendações
Esta seção descreve vários padrões impactantes para Node.js aplicativos que recomendamos que você siga.
Escolha planos de Serviço de Aplicativo de única vCPU
Quando você cria um aplicativo de função que usa o plano do Serviço de Aplicativo, recomendamos que você selecione um plano de vCPU única em vez de um plano com várias vCPUs. Atualmente, o Functions executa funções Node.js de forma mais eficiente em máquinas virtuais de vCPU única, e usar máquinas virtuais maiores não produz as melhorias de desempenho esperadas. Quando necessário, você pode expandir manualmente adicionando mais instâncias de VM de vCPU única ou habilitar o dimensionamento automático. Para obter mais informações, consulte Dimensionar a contagem de instâncias manualmente ou automaticamente.
Executar a partir de um arquivo de pacote
Quando se desenvolvem Azure Functions no modelo de alojamento serverless, os cold starts são uma realidade. Arranque a frio refere-se à primeira vez que a sua função é iniciada após um período de inatividade, levando mais tempo para arrancar. Para aplicativos Node.js com grandes árvores de dependência em particular, o arranque a frio pode ser significativo. Para acelerar o processo de arranque a frio, execute as suas funções como um ficheiro de pacote sempre que possível. Muitos métodos de implantação usam este modelo por padrão, mas se estiver a enfrentar grandes inicializações a frio, verifique se está a executar dessa maneira.
Usar um único cliente estático
Quando usar um cliente específico de serviço numa aplicação Azure Functions, não crie um novo cliente com cada invocação de função porque pode atingir limites de ligação. Em vez disso, crie um único cliente estático no escopo global. Para mais informações, consulte gerir ligações em Azure Functions.
Utilize async e await
Ao escrever Azure Functions em Node.js, deve escrever código usando as palavras-chave async e await. Escrever código usando async e await em vez de callbacks ou .then e .catch com Promises ajuda a evitar dois problemas frequentes:
- Lançar exceções não detetadas que travam o processo de Node.js, potencialmente afetando a execução de outras funções.
- Comportamento inesperado, como logs ausentes do
context.log, devido a chamadas assíncronas que não são aguardadas corretamente.
No exemplo a seguir, o método fs.readFile assíncrono é invocado com uma função de retorno de chamada error-first como seu segundo parâmetro. Este código causa ambos os problemas mencionados anteriormente. Uma exceção que não é explicitamente tratada no escopo correto pode interromper todo o processo (problema #1). Retornar sem garantir que o callback termine significa que a resposta HTTP às vezes fica com um corpo vazio (problema #2).
// 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 };
},
});
No exemplo a seguir, o método fs.readFile assíncrono é invocado com uma função de retorno de chamada error-first como seu segundo parâmetro. Este código causa ambos os problemas mencionados anteriormente. Uma exceção que não é explicitamente tratada no escopo correto pode interromper todo o processo (problema #1). Chamar o método obsoleto context.done() fora do contexto de callback pode sinalizar que a execução da função terminou antes que o arquivo seja lido (problema #2). Neste exemplo, chamar context.done() muito cedo resulta em entradas de log ausentes começando com Data from file:.
// 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();
};
Para ajudar a evitar ambos os problemas, use as palavras-chave async e await. A maioria das APIs no ecossistema Node.js foram convertidas para suportar promessas de alguma forma. Por exemplo, a partir da v14, o Node.js fornece uma fs/promises API para substituir a API de callback fs.
No exemplo a seguir, quaisquer exceções não tratadas lançadas durante a execução da função só falham a invocação individual que gerou a exceção. A await palavra-chave significa que as etapas seguintes readFile só são executadas depois de concluídas.
// 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;
}
},
});
Com async e await, você também não precisa chamar o callback context.done().
// 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}`);
};
Resolver problemas
Consulte o Guia de solução de problemas do Node.js.
Próximos passos
Para obter mais informações, consulte os seguintes recursos: