Функции Azure Node.js справочник разработчиков

В этом справочнике рассматривается, как разрабатывать Функции Azure с помощью JavaScript и TypeScript с помощью пакета @azure/functions npm. Для общего обзора концепций Функции Azure, которые используются во всех языках, см. ссылку на разработчика Функции Azure.

Ресурс Link
Создайте свою первую JavaScript-функцию Visual Studio Code/CLI
Создайте свою первую функцию TypeScript Visual Studio Code/CLI
Сценарии и образцы JavaScript/Машинописный текст
Справочник по API @azure/functions API

Примечание.

В этой статье представлен контент для конкретной версии модели программирования на основе селектора в верхней части страницы. Выбранная вами версия должна соответствовать версии @azure/functions вашего NPM-пакета. Нельзя смешивать функции v3 и v4 в одном приложении. Если в вашем package.json нет пакета, по умолчанию используется v3.

Модель программирования

Функции Azure для Node.js поддерживает две версии моделей программирования. Новые проекты должны использовать v4.

Функция v4 (рекомендуется) v3
Status Общедоступная версия GA (техническое обслуживание)
@azure/functions пакет 4.x 3.x
Регистрация функции Ориентированный на код (app.http(), app.timer()) На основе файлов (function.json)
Структура файлов Гибкий Исправлено (одна папка на каждую функцию)
Версия среды выполнения функций 4.25+ 4.x
версии Node.js 24.x, 22.x 24.x, 22.x

В модели программирования Node.js v4 вы регистрируете функции, импортируя app объект из @azure/functions и вызывая специфические для триггера методы. Функции определяются напрямую в вашем коде с гибкой структурой файлов. Каждая функция имеет один триггер , который запускает своё выполнение, а также может иметь связки — декларативные соединения с другими сервисами для чтения входных данных или записи выходных. Для получения дополнительной информации смотрите раздел Триггеры и привязки.

В модели v4 вы:

  • Регистрируйте функции с помощью методов, специфичных для триггеров, таких как app.http(), app.timer() и app.storageQueue().
  • Получите доступ к входу триггера как к первому аргументу обработчику (например, HttpRequest).
  • Верните первичный выход напрямую от функции обработчика.
  • Используйте context.extraInputs.get() для чтения из дополнительных входных привязок, таких как Хранилище BLOB-объектов.
  • Используйте context.extraOutputs.set() для записи в дополнительные выходные привязки, например очереди.
  • Каждая функция имеет ровно один триггер, но может иметь несколько дополнительных входов и выходов.
  • Вы можете кэшировать данные в глобальных переменных для повторного использования между вызовами, но не полагайтесь на сохранение этого состояния. Среда выполнения может в любой момент перезапустить ваш рабочий процесс.

В модели программирования Node.js v3 каждая функция определяется с помощью function.json конфигурационного файла и соответствующего кода JavaScript или TypeScript. Вы организуете функции в отдельных папках с определёнными структурами файлов. Каждая функция имеет один триггер , который запускает своё выполнение, а также может иметь связки — декларативные соединения с другими сервисами для чтения входных данных или записи выходных. Для получения дополнительной информации смотрите раздел Триггеры и привязки.

В модели v3 вы:

  • Определите триггеры и привязки в function.json файле. Используйте direction: "in" для входов и direction: "out" выходов.
  • Получите доступ к входному параметру триггера в качестве второго аргумента обработчика или получите его из context.bindings.
  • Задайте выходные данные, присвоив значения context.bindings (например, context.bindings.outputQueue). Для HTTP используйте context.res.
  • Проектам TypeScript требуется свойство scriptFile в function.json, которое указывает на скомпилированный JavaScript-файл.
  • Каждая функция имеет ровно один триггер, но может иметь несколько входных и выходных связей.
  • Вы можете кэшировать данные в глобальных переменных для повторного использования между вызовами, но не полагайтесь на сохранение этого состояния. Среда выполнения может в любой момент перезапустить ваш рабочий процесс.

Примеры

Ниже приведена простая функция, которая отвечает на HTTP-запрос:

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

app.http('httpTrigger', {
    methods: ['GET', 'POST'],
    authLevel: 'anonymous',
    handler: async (request, context) => {
        const name = request.query.get('name') || 'World';
        context.log('HTTP trigger function processed a request.');

        return { body: `Hello, ${name}!` };
    }
});

Следующий пример, не относящийся к HTTP, использует триггер таймера:

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

app.timer('cleanupTimer', {
  schedule: '0 */5 * * * *',
  handler: async (myTimer, context) => {
    context.log('Timer trigger function ran at', new Date().toISOString());
  }
});

В следующем примере показан HTTP-триггер с выходной привязкой к очереди:

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

const queueOutput = output.storageQueue({
  queueName: 'work-items',
  connection: 'AzureWebJobsStorage'
});

app.http('submitWorkItem', {
  methods: ['POST'],
  extraOutputs: [queueOutput],
  handler: async (request, context) => {
    const body = await request.json();
    context.extraOutputs.set(queueOutput, JSON.stringify(body));
    return { status: 202, jsonBody: { accepted: true } };
  }
});

Ниже приведена простая функция, которая отвечает на HTTP-запрос:

{
  "bindings": [
    {
      "authLevel": "anonymous",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": ["get", "post"]
    },
    {
      "type": "http",
      "direction": "out",
      "name": "res"
    }
  ]
}
module.exports = async function (context, req) {
    const name = (req.query.name || (req.body && req.body.name)) || 'World';
    context.log('HTTP trigger function processed a request.');

    context.res = {
        body: `Hello, ${name}!`
    };
};

Следующий пример, не относящийся к HTTP, использует триггер таймера:

{
  "bindings": [
    {
      "name": "myTimer",
      "type": "timerTrigger",
      "direction": "in",
      "schedule": "0 */5 * * * *"
    }
  ]
}
module.exports = async function (context, myTimer) {
    context.log('Timer trigger function ran at', new Date().toISOString());
};

В следующем примере показан HTTP-триггер с выходной привязкой к очереди:

{
  "bindings": [
    {
      "authLevel": "function",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": ["post"]
    },
    {
      "type": "queue",
      "direction": "out",
      "name": "workItems",
      "queueName": "work-items",
      "connection": "AzureWebJobsStorage"
    },
    {
      "type": "http",
      "direction": "out",
      "name": "res"
    }
  ]
}
module.exports = async function (context, req) {
    const payload = req.body || {};
    context.bindings.workItems = JSON.stringify(payload);
    context.res = {
        status: 202,
        body: { accepted: true }
    };
};

Создание функционального приложения

В этом разделе рассматриваются основные компоненты для создания и структурирования вашего функционального приложения Node, включая @azure/functions библиотеку, структуру проекта и управление пакетами.

@azure/functions Библиотека

Библиотека @azure/functions TypeScript/JavaScript предоставляет базовые типы и функции, которые используются для взаимодействия со средой выполнения Функции Azure. Чтобы просмотреть все доступные типы и методы, посетите @azure/functions API.

Ваш код функции может использовать @azure/functions для:

  • Регистрируйте функции и определяйте триггеры (модель v4).
  • Получить доступ к сильно типизированным входным данным триггера (например, HttpRequest, Timer).
  • Создайте типизированные значения вывода (например HttpResponseInit).
  • Взаимодействовать с данными контекста и связывания, предоставленными во время выполнения.

Если вы используете @azure/functions в приложении, добавьте его в зависимости проекта:

{
  "dependencies": {
    "@azure/functions": "^4.0.0"
  }
}

Примечание.

Библиотека @azure/functions определяет поверхность программирования для Node.js Функции Azure, но это не универсальный SDK. Используйте его специально для разработки и запуска функций в среде выполнения Функции Azure.

Конфигурация TypeScript

Для максимально комфортной разработки на TypeScript убедитесь, что tsconfig.json содержит необходимую конфигурацию:

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es6",
    "outDir": "dist",
    "rootDir": ".",
    "sourceMap": true,
    "strict": false,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  }
}

Структура папок

Для проекта на JavaScript требуется структура папок, показанная в следующем примере:

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

Основная папка проекта, <project_root>, может содержать следующие файлы:

  • .vscode/: (необязательно) содержит хранимую конфигурацию Visual Studio Code. Дополнительные сведения см. в разделе настройки Visual Studio Code.
  • myFirstFunction/function.json: содержит конфигурацию триггера, входных данных и выходных данных функции. Имя каталога определяет имя функции.
  • myFirstFunction/index.js: хранит код функции. Чтобы изменить путь к файлу по умолчанию, используйте scriptFile.
  • .funcignore: (необязательно) объявляет файлы, которые не должны публиковаться в Azure. Обычно этот файл содержит .vscode/, чтобы игнорировать настройки редактора, test/, чтобы игнорировать тестовые случаи, и local.settings.json, чтобы локальные настройки приложения не публиковались.
  • host.json: содержит параметры глобальной конфигурации, влияющие на все функции в экземпляре приложения-функции. Этот файл публикуется в Azure. При локальном запуске поддерживаются не все параметры. Дополнительные сведения см. в разделе host.json.
  • local.settings.json: Используется для хранения параметров приложения и строк подключения при локальном запуске. Этот файл не публикуется в Azure. Дополнительные сведения см. в разделе local.settings.file.
  • package.json: Содержит опции конфигурации, такие как список зависимостей пакета, основная точка входа и скрипты.

JavaScript-проект следует рекомендованной структуре папок в следующем примере:

<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

Основная папка проекта, <project_root>, может содержать следующие файлы:

  • .vscode/: (необязательно) содержит хранимую конфигурацию Visual Studio Code. Дополнительные сведения см. в разделе настройки Visual Studio Code.
  • src/functions/: расположение по умолчанию для всех функций и связанных с ними триггеров и привязок.
  • test/: (необязательно) Содержит тестовые варианты приложения-функции.
  • .funcignore: (необязательно) объявляет файлы, которые не должны публиковаться в Azure. Обычно этот файл содержит .vscode/, чтобы игнорировать настройки редактора, test/, чтобы игнорировать тестовые случаи, и local.settings.json, чтобы локальные настройки приложения не публиковались.
  • host.json: содержит параметры глобальной конфигурации, влияющие на все функции в экземпляре приложения-функции. Этот файл публикуется в Azure. При локальном запуске поддерживаются не все параметры. Дополнительные сведения см. в разделе host.json.
  • local.settings.json: Используется для хранения параметров приложения и строк подключения при локальном запуске. Этот файл не публикуется в Azure. Дополнительные сведения см. в разделе local.settings.file.
  • package.json: Содержит опции конфигурации, такие как список зависимостей пакета, основная точка входа и скрипты.

Управление пакетами

Эффективное управление пакетами крайне важно в проектах Функции Azure на Node.js. В этом разделе рассматривается управление зависимостями, конфигурацию пакетов и лучшие практики поддержания зависимостей ваших функциональных приложений.

Управление зависимостями

Все Node.js Функции Azure проекты используют NPM для управления пакетами. Ваш package.json файл определяет конфигурацию проекта, зависимости и скрипты, необходимые для создания и запуска ваших функций.

Основная структура package.json:

{
  "name": "my-functions-app",
  "version": "1.0.0",
  "description": "Azure Functions Node.js app",
  "main": "src/index.js",
  "scripts": {
    "build": "tsc",
    "watch": "tsc -w",
    "prestart": "npm run build",
    "start": "func start",
    "test": "jest"
  },
  "dependencies": {
    "@azure/functions": "^4.0.0"
  },
  "devDependencies": {
    "@azure/functions-core-tools": "^4.0.4670",
    "@types/node": "^18.0.0",
    "typescript": "^4.0.0",
    "jest": "^29.0.0"
  }
}

Зависимости времени выполнения и разработки

Разделяйте зависимости соответствующим образом:

Зависимости во время выполнения (dependencies):

  • @azure/functions: Основная библиотека Функции Azure
  • Библиотеки бизнес-логики (lodash, axios и аналогичные пакеты)
  • Драйверы баз данных (mongodb, mssql и аналогичные пакеты)
  • пакеты Azure SDK (@azure/storage-blob, @azure/cosmos, и аналогичные пакеты)

Зависимости от развития (devDependencies):

  • Компилятор TypeScript и определения типов
  • Тестирование фреймворков (Jest, Mocha)
  • Инструменты сборки и линтеры
  • Функции Azure Core Tools (для локальной разработки)

Специфичные пакеты для TypeScript

Для проектов TypeScript включайте следующие основные зависимости разработки:

{
  "devDependencies": {
    "@types/node": "^18.0.0",
    "typescript": "^4.0.0",
    "@typescript-eslint/eslint-plugin": "^5.0.0",
    "@typescript-eslint/parser": "^5.0.0"
  }
}

Безопасность и обновления

Регулярно обновляйте свои зависимости для устранения уязвимостей безопасности:

# Check for outdated packages
npm outdated

# Update packages
npm update

# Audit for security issues
npm audit
npm audit fix

Запуск и отладка

Этот раздел охватывает локальную разработку, методы отладки и стратегии тестирования для Node.js Функции Azure.

Настройка локальной разработки

Prerequisites:

Действия по настройке:

  1. Установите зависимости:

    npm install
    
  2. Постройте проекты TypeScript:

    npm run build
    
  3. Начните локальное время выполнения:

    npm start
    # or directly:
    func start
    

Конфигурация среды

Настройте вашу локальную среду разработки, используя local.settings.json:

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "node",
    "NODE_ENV": "development",
    "CUSTOM_ENV_VARIABLE": "local-value"
  },
  "Host": {
    "LocalHttpPort": 7071,
    "CORS": "*",
    "CORSCredentials": false
  }
}

Отладка

Отладка Visual Studio Code:

Создайте .vscode/launch.json:

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Attach to Node Functions",
      "type": "node",
      "request": "attach",
      "port": 9229,
      "preLaunchTask": "func: host start"
    }
  ]
}

Создайте .vscode/tasks.json:

{
  "version": "2.0.0",
  "tasks": [
    {
      "type": "func",
      "label": "func: host start",
      "command": "host start",
      "problemMatcher": "$func-node-watch",
      "isBackground": true,
      "options": {
        "cwd": "${workspaceFolder}"
      }
    }
  ]
}

Отладка командной строки:

# Start with debugging enabled
func start --p <port>

# For TypeScript, ensure you build first
npm run build
func start --p 9229

Развертывание

В этом разделе рассматриваются стратегии развертывания, интеграция CI/CD и лучшие производственные практики для Node.js Функции Azure.

Методы развертывания

1. Развертывание Visual Studio Code:

  • Установите расширение Функции Azure.
  • Кликните правой кнопкой мыши по функциональному приложению в панели Azure.
  • Выберите «Развернуть в функциональное приложение».

2. Функции Azure Core Tools:

# Deploy to Azure
func azure functionapp publish <FunctionAppName>

# Deploy with custom settings
func azure functionapp publish <FunctionAppName> --build local --publish-local-settings

3. Azure CLI deployment:

# Deploy from local folder
az functionapp deployment source config-zip \
  --resource-group <ResourceGroupName> \
  --name <FunctionAppName> \
  --src <PathToZipFile>

Рабочая конфигурация

Application settings in Azure:

Настройте переменные среды для производства:

  • WEBSITE_NODE_DEFAULT_VERSION: установите значение ~18 или ~20.
  • FUNCTIONS_WORKER_RUNTIME: задано значение node.
  • Строки подключения и ключи API как защищённые настройки приложения.
  • NODE_ENV: задано значение production.

Триггеры и привязки

Функции Azure используют триггеры для запуска выполнения функций и привязок для подключения кода к другим службам, таким как хранилище, очереди и базы данных. В модели программирования Node.js вы объявляете привязки по-разному в зависимости от версии модели.

Существуют два основных типа привязок:

  • Триггеры (входные данные, запускающие функцию)
  • Входные и выходные данные (дополнительные источники данных или назначения)

Дополнительные сведения о доступных триггерах и привязках см. в разделе "Триггеры и привязки" в Функциях Azure.

Пример: триггер таймера с входными данными объектов Blob

Эта функция срабатывает каждые 10 минут, считывает данные из объекта Blob, используя дополнительные входные данные, и записывает содержимое объекта Blob в журнал.

const { app, input } = require('@azure/functions');

let CACHED_BLOB_DATA = null;

const blobInput = input.storageBlob({
    connection: 'BLOB_CONNECTION_SETTING',
    path: 'mycontainer/myblob.txt'
});

app.timer('TimerTriggerWithBlob', {
    schedule: '0 */10 * * * *',
    extraInputs: [blobInput],
    handler: async (myTimer, context) => {
        if (CACHED_BLOB_DATA === null) {
            // Read blob content and cache it
            CACHED_BLOB_DATA = context.extraInputs.get(blobInput);
            context.log(`Blob content cached: ${CACHED_BLOB_DATA?.substring(0, 100)}...`);
        }

        context.log(`Timer function executed at: ${new Date().toISOString()}`);
        context.log(`Using cached data of length: ${CACHED_BLOB_DATA?.length || 0}`);
    }
});

Эта функция запускается каждые 10 минут, считывает данные из BLOB-объекта с помощью конфигурации привязок и записывает содержимое BLOB-объекта в журнал.

{
  "scriptFile": "index.js",
  "bindings": [
    {
      "name": "myTimer",
      "type": "timerTrigger",
      "direction": "in",
      "schedule": "0 */10 * * * *"
    },
    {
      "name": "blobInput",
      "type": "blob",
      "direction": "in",
      "path": "mycontainer/myblob.txt",
      "connection": "AzureWebJobsStorage"
    }
  ]
}
let CACHED_BLOB_DATA = null;

module.exports = async function (context, myTimer) {
    if (CACHED_BLOB_DATA === null) {
        // Read blob content and cache it
        CACHED_BLOB_DATA = context.bindings.blobInput;
        context.log(`Blob content cached: ${CACHED_BLOB_DATA?.substring(0, 100)}...`);
    }

    context.log(`Timer function executed at: ${new Date().toISOString()}`);
    context.log(`Using cached data of length: ${CACHED_BLOB_DATA?.length || 0}`);
};

Пример: HTTP-триггер с выходной привязкой к очереди

Эта функция запускается при HTTP-запросе, записывает сообщение в очередь хранения и возвращает HTTP-ответ.

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

const queueOutput = output.storageQueue({
    connection: 'AzureWebJobsStorage',
    queueName: 'myqueue'
});

app.http('httpTriggerWithQueue', {
    methods: ['GET', 'POST'],
    extraOutputs: [queueOutput],
    handler: async (request, context) => {
        const name = request.query.get('name') || 'World';
        const message = {
            id: context.invocationId,
            name: name,
            timestamp: new Date().toISOString()
        };

        // Write to queue output
        context.extraOutputs.set(queueOutput, JSON.stringify(message));
        context.log(`Message sent to queue: ${JSON.stringify(message)}`);

        return {
            body: `Hello, ${name}! Message queued successfully.`
        };
    }
});

Эта функция запускается при HTTP-запросе, записывает сообщение в очередь хранения и возвращает HTTP-ответ.

{
  "scriptFile": "index.js",
  "bindings": [
    {
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": ["get", "post"]
    },
    {
      "type": "http",
      "direction": "out",
      "name": "$return"
    },
    {
      "type": "queue",
      "direction": "out",
      "name": "outputQueue",
      "queueName": "myqueue",
      "connection": "AzureWebJobsStorage"
    }
  ]
}
module.exports = async function (context, req) {
    const name = (req.query.name || (req.body && req.body.name)) || 'World';
    const message = {
        id: context.invocationId,
        name: name,
        timestamp: new Date().toISOString()
    };

    // Write to queue output
    context.bindings.outputQueue = JSON.stringify(message);
    context.log(`Message sent to queue: ${JSON.stringify(message)}`);

    return {
        status: 200,
        body: `Hello, ${name}! Message queued successfully.`
    };
};

Объекты app, trigger, input и output, экспортируемые модулем @azure/functions, предоставляют типовые методы для большинства типов. Для всех типов, которые не поддерживаются, предоставляется метод, generic позволяющий вручную указать конфигурацию. Этот generic метод можно также использовать, если вы хотите изменить параметры по умолчанию, предоставляемые типовым методом.

В следующем примере показана простая функция, активироваемая HTTP, с помощью универсальных методов вместо методов, относящихся к типу.

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!` };
  },
});

::: зональный конец

Контекст вызова

Каждый вызов вашей функции получает объект вызова context . Используйте этот объект для чтения входных данных, настройки выходов, записи в журналы и доступа к различным метаданным. В модели v3 вы всегда передаёте объект контекста как первый аргумент обработчику.

Объект context включает следующие свойства:

Свойство Описание
invocationId Идентификатор вызова текущей функции.
executionContext См. контекст выполнения.
bindings См. привязки.
bindingData Метаданные о входном триггере для этого вызова, исключая само значение. Например, триггер концентратора событий имеет enqueuedTimeUtc свойство.
traceContext Контекст распределенной трассировки. Дополнительные сведения см. в разделе Trace Context.
bindingDefinitions Конфигурация входных и выходных данных, как определено в function.json.
req См . HTTP-запрос.
res См HTTP-ответ.

контекст.executionContext

Объект context.executionContext имеет следующие свойства.

Свойство Описание
invocationId Идентификатор вызова текущей функции.
functionName Название функции, которую вы вызываете. Имя папки, function.json содержащей файл, определяет имя функции.
functionDirectory Папка, содержащая function.json файл.
retryContext См. контекст повторных попыток.

context.executionContext.retryContext

Объект context.executionContext.retryContext имеет следующие свойства.

Свойство Описание
retryCount Число, представляющее текущую попытку повтора.
maxRetryCount Максимальное количество повторных попыток выполнения. Значение -1 указывает на неограниченное число повторных попыток.
exception Исключение, вызвавшее повторную попытку.

Объект context.bindings

Используйте context.bindings объект для чтения входных данных или настройки выходов. Следующий пример — это триггер очереди хранилища , который копирует context.bindingsвход блока хранения в выход блока хранилища. Содержимое сообщения очереди заменяет {queueTrigger}, которое используется как имя файла, подлежащее копированию, с помощью выражения привязки.

{
    "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;
};

context.done

Метод context.done не рекомендуется. До того как Функции Azure начал поддерживать асинхронные функции, вы показывали, что ваша функция выполнена, вызывая context.done():

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

Удалите вызов context.done(). Отметьте свою функцию как асинхронную, чтобы она возвращала обещание (даже если вы ничего не await сделаете). Как только функция завершится (другими словами, возвращенное обещание разрешается), модель версии 3 знает, что ваша функция выполнена.

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

Каждый вызов вашей функции получает объект вызова context . Этот объект содержит информацию о вашем вызове и методах логирования. В модели v4 вы обычно передаёте context объект как второй аргумент обработчику.

Класс InvocationContext содержит следующие свойства:

Свойство Описание
invocationId Идентификатор вызова текущей функции.
functionName Имя функции.
extraInputs Используется для получения значений дополнительных входных данных. Дополнительные сведения см. в дополнительных входных данных и выходных данных.
extraOutputs Используется для задания значений дополнительных выходных данных. Дополнительные сведения см. в дополнительных входных данных и выходных данных.
retryContext См. контекст повторных попыток.
traceContext Контекст распределенной трассировки. Дополнительные сведения см. в разделе Trace Context.
triggerMetadata Метаданные о входных параметрах триггера для этого вызова, за исключением самого значения. Например, триггер концентратора событий имеет enqueuedTimeUtc свойство.
options Параметры, используемые при регистрации функции, после их проверки и явного задания значений по умолчанию.

Контекст повторной попытки

Объект retryContext имеет следующие свойства.

Свойство Описание
retryCount Число, представляющее текущую попытку повтора.
maxRetryCount Максимальное количество повторных попыток выполнения. Значение -1 указывает на неограниченное число повторных попыток.
exception Исключение, вызвавшее повторную попытку.

Дополнительные сведения см. в разделе retry-policies.

Ведение журнала

В Функции Azure используйте context.log() для записи логов. Функции Azure интегрируется с приложение Azure Insights, чтобы лучше записывать журналы приложений-функций. Application Insights, являясь частью Azure Monitor, предоставляет средства для сбора, визуализации и анализа как журналов приложений, так и выходных данных трассировки. Дополнительные сведения см. в статье monitoring Функции Azure.

Примечание.

Если использовать альтернативный метод Node.js console.log , логи на уровне приложений отслеживаются, но не связаны с какой-либо конкретной функцией. Используйте context для логирования вместо console того, чтобы все логи были связаны с определённой функцией.

В следующем примере записывается журнал на уровне сведений по умолчанию, включая идентификатор вызова:

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

Уровни журнала

В дополнение к стандартному context.log методу используйте следующие методы для записи логов на определённых уровнях:

Метод Описание
context.log.error() Записывает событие уровня ошибки в журналы.
context.log.warn() Записывает событие уровня предупреждения в журналы.
context.log.info() Записывает событие уровня информации в журналы.
context.log.verbose() Записывает событие уровня трассировки в журналы.
Метод Описание
context.trace() Записывает событие уровня трассировки в журналы.
context.debug() Записывает событие уровня отладки в журналы.
context.info() Записывает событие уровня информации в журналы.
context.warn() Записывает событие уровня предупреждения в журналы.
context.error() Записывает событие уровня ошибки в журналы.

Настройка уровня журнала

Функции позволяют задать порог для отслеживания и просмотра журналов. Чтобы задать пороговое значение, используйте logging.logLevel свойство в host.json файле. Это свойство позволяет определить уровень по умолчанию для всех функций или порог для каждой отдельной функции. Дополнительные сведения см. в разделе Настройка мониторинга для Функций Azure.

Отслеживание настраиваемых данных

По умолчанию Функции Azure записывает выходные данные в виде трассировок в Application Insights. Для большего контроля используйте Application Insights Node.js SDK , чтобы отправлять пользовательские журналы, метрики и зависимости в ваш экземпляр Application Insights.

Примечание.

Методы в пакете SDK Node.js Application Insights могут изменяться с течением времени. В примерах, показанных здесь, могут быть незначительные отличия синтаксиса. Последние примеры использования API см. в документации по пакету SDK для Application Insights Node.js.

Для распределённого трассирования в модели программирования Node.js v4 используйте пакет @azure/functions-opentelemetry-instrumentation вместо Application Insights SDK. Этот пакет предоставляет автоматическое инструментирование на основе OpenTelemetry для Функции Azure. Дополнительные сведения см. в репозитории OpenTelemetry Функции Azure инструментирование для 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,
  });
};

Параметр tagOverrides присваивает параметру operation_Id значение идентификатора вызова функции. Эта настройка позволяет сопоставлять все автоматически сгенерированные и пользовательские логи для заданного вызова функции.

Триггеры HTTP

Триггеры HTTP и веб-хук используют объекты запроса и ответа для представления HTTP-сообщений.

Триггеры HTTP и веб-перехватчика используют объекты HttpRequest и HttpResponse для представления HTTP-сообщений. Классы представляют подмножество стандарта fetch, с использованием пакета Node.js .

HTTP-запрос

Получить доступ к запросу можно несколькими способами:

  • В качестве второго аргумента функции:

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

  • Из context.req свойства:

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

  • Из именованных входных привязок: Эта опция работает так же, как и любое не-HTTP-привязание. Имя привязки в function.json должно соответствовать ключу на context.bindings, или "request1" в следующем примере:

    {
      "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}"`);
    

Объект HttpRequest имеет следующие свойства.

Свойство Тип Описание
method string Метод HTTP-запроса, используемый для вызова этой функции.
url string URL-адрес запроса.
headers Record<string, string> Заголовки HTTP-запроса. Этот объект чувствителен к регистру. Используйте вместо этого request.getHeader('header-name'), так как он не учитывает регистр.
query Record<string, string> Запрос ключей и значений строковых параметров из URL-адреса.
params Record<string, string> Ключи и значения параметров маршрута.
user HttpRequestUser \| null Объект, представляющий пользователя, вошедшего в систему, через аутентификацию через Функции, аутентификацию через SWA или null, если пользователь не вошел в систему.
body Buffer \| string \| any Если тип носителя — application/octet-stream или multipart/*, body это буфер. Если значение является строкой с возможностью синтаксического анализа JSON, body является объектом синтаксического анализа. В противном случае, это строка body.
rawBody string Тело в виде строки. Несмотря на название, это свойство не возвращает буфер.
bufferBody Buffer Тело в качестве буфера.

Вы можете обращаться к запросу как к первому аргументу обработчика для функции, активируемой HTTP-запросом.

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

Объект HttpRequest имеет следующие свойства.

Свойство Тип Описание
method string Метод HTTP-запроса, используемый для вызова этой функции.
url string URL-адрес запроса.
headers Headers Заголовки HTTP-запроса.
query URLSearchParams Запрос ключей и значений строковых параметров из URL-адреса.
params Record<string, string> Ключи и значения параметров маршрута.
user HttpRequestUser \| null Объект, представляющий пользователя, вошедшего в систему, через аутентификацию через Функции, аутентификацию через SWA или null, если пользователь не вошел в систему.
body ReadableStream \| null Тело в виде читаемого потока.
bodyUsed boolean Логическое значение, указывающее, считывается ли текст.

Чтобы получить доступ к телу запроса или ответа, используйте следующие методы:

Метод Тип возвращаемых данных
arrayBuffer() Promise<ArrayBuffer>
blob() Promise<Blob>
formData() Promise<FormData>
json() Promise<unknown>
text() Promise<string>

Примечание.

Функции тела можно выполнить только один раз. Последующие вызовы возвращают пустые строки или объекты ArrayBuffer.

HTTP-ответ

Вы можете настроить ответ несколькими способами. Например, вы можете использовать:

  • context.res Задайте свойство:

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

  • Верните ответ: если ваша функция асинхронная и вы задаете имя привязки как $return в вашем function.json, вы можете вернуть ответ напрямую, вместо того чтобы задавать его в context.

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

  • Установите именованный выходной привязок: Эта опция работает так же, как и любое не-HTTP-привязание. Имя привязки в function.json должно соответствовать ключу на context.bindings, или "response1" в следующем примере:

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

  • Вызов context.res.send(): этот параметр не рекомендуется. Он неявно вызывает context.done() , и вы не можете использовать его в асинхронной функции.

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

При создании нового объекта при настройке ответа этот объект должен соответствовать интерфейсу HttpResponseSimple , который имеет следующие свойства:

Свойство Тип Описание
headers Record<string, string> (необязательно) Заголовки HTTP-ответа.
cookies Cookie[] (необязательно) Файлы cookie ответа HTTP.
body any (необязательно) Текст ответа HTTP.
statusCode number (необязательно) Код состояния HTTP-ответа. Если значение не задано, по умолчанию используется 200значение .
status number (необязательно) То же самое, что statusCode. Это свойство игнорируется, если statusCode задано.

Можно также изменить context.res объект, не перезаписав его. Объект по умолчанию context.res использует HttpResponseFull интерфейс, который поддерживает следующие методы в дополнение к свойствам HttpResponseSimple :

Метод Описание
status() Устанавливает статус.
setHeader() Задает поле заголовка. ПРИМЕЧАНИЕ:res.set() И res.header() тоже поддерживаются и делают то же самое.
getHeader() Получает поле для заголовка. ПРИМЕЧАНИЕ:res.get() также поддерживается и делает то же самое.
removeHeader() Удаляет заголовок.
type() Задает заголовок content-type.
send() Этот метод является устаревшим. Он задает тело и вызывает context.done(), чтобы указать на завершение функции синхронизации. ПРИМЕЧАНИЕ:res.end() Это также поддерживается и выполняет ту же функцию.
sendStatus() Этот метод является устаревшим. Он задает код состояния и вызовы context.done() для указания завершения функции синхронизации.
json() Этот метод является устаревшим. Он устанавливает "content-type" на "application/json", устанавливает тело и вызывает context.done() для указания завершения функции синхронизации.

Вы можете настроить ответ несколькими способами. Например, вы можете использовать:

  • Простой интерфейс с типом HttpResponseInit: Эта опция — самый лаконичный способ возврата ответов.

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

Интерфейс HttpResponseInit имеет следующие свойства:

Свойство Тип Описание
body BodyInit (необязательно) Текст ответа HTTP в виде одного из ArrayBuffer, AsyncIterable<Uint8Array>BlobFormDataIterable<Uint8Array>NodeJS.ArrayBufferViewURLSearchParamsnullили .string
jsonBody any (необязательно) Текст ответа HTTP, сериализуемый в формате JSON. Если задано, HttpResponseInit.body свойство игнорируется в пользу этого свойства.
status number (необязательно) Код состояния HTTP-ответа. Если значение не задано, по умолчанию используется 200значение .
headers HeadersInit (необязательно) Заголовки HTTP-ответа.
cookies Cookie[] (необязательно) Файлы cookie ответа HTTP.
  • Как класс с типом HttpResponse: этот параметр предоставляет вспомогательные методы для чтения и изменения различных частей ответа, таких как заголовки.

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

Класс HttpResponse принимает необязательный HttpResponseInit аргумент в качестве аргумента его конструктора и имеет следующие свойства:

Свойство Тип Описание
status number Код состояния HTTP-ответа.
headers Headers Заголовки HTTP-ответа.
cookies Cookie[] Файлы cookie ответа HTTP.
body ReadableStream | null Тело в виде читаемого потока.
bodyUsed boolean Логическое значение, указывающее, считывается ли текст.

HTTP-потоки

HTTP-потоки — это функция, которая упрощает обработку больших данных, потоковую передачу ответов OpenAI, доставку динамического содержимого и поддержку других основных сценариев HTTP. Он позволяет передавать запросы и ответы от конечных точек HTTP в приложении-функции Node.js. Используйте http-потоки в сценариях, когда приложению требуется обмен данными в режиме реального времени и взаимодействие между клиентом и сервером по протоколу HTTP. Вы также можете использовать HTTP-потоки для получения оптимальной производительности и надежности приложений при использовании HTTP.

Внимание

Http-потоки не поддерживаются в модели версии 3. Обновите модель версии 4 , чтобы использовать функцию потоковой передачи HTTP. Существующие HttpRequest и HttpResponse типы в модели программирования версии 4 уже поддерживают различные способы обработки текста сообщения, включая поток.

Предварительные требования

Включение потоков

Выполните следующие действия, чтобы включить HTTP-потоки в приложении-функции в Azure и в локальных проектах:

  1. Если планируется потоковая передача больших объемов данных, измените параметр FUNCTIONS_REQUEST_BODY_SIZE_LIMIT в Azure. Максимально допустимый размер тела запроса по умолчанию — 104857600, что ограничивает размер запросов примерно до 100 МБ.

  2. Для FUNCTIONS_REQUEST_BODY_SIZE_LIMIT также добавьте в файл local.settings.json.

  3. Добавьте следующий код в ваше приложение в любой файл, включенный вашим главным полем.

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

Примеры потоков

Следующий пример показывает HTTP-триггерную функцию, которая получает данные через HTTP-запрос POST. Функция передаёт эти данные в заданный выходной файл:

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!' };
    },
});

В следующем примере показана функция, спровоцированная через HTTP, которая транслирует содержимое файла в ответ на входящие запросы HTTP GET:

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 };
    },
});

Для готового к запуску примера приложения, использующего потоки, посмотрите этот пример на GitHub.

Соображения по потокам

  • Используйте request.body, чтобы получить максимальную пользу от использования потоков. Вы всё ещё можете использовать такие методы, как request.text(), которые всегда возвращают тело ответа в виде строки.

Хуки

Модель v3 не поддерживает крючки. Обновите до модели v4, чтобы использовать хуки.

Используйте хук для выполнения кода на различных этапах жизненного цикла Функции Azure. Порядок регистрации хуков определяет порядок их выполнения. Вы можете регистрировать хуки из любого файла в приложении. Существует два диапазона зацепок: уровень «приложения» и уровень «вызова».

Крючки вызова

Хуки вызова срабатывают один раз при каждом вызове вашей функции. Хук preInvocation выполняется до выполнения функции, а хук postInvocation — после выполнения функции. По умолчанию ваш крюк выполняется для всех типов триггеров, но вы также можете фильтровать по типу. В следующем примере показано, как зарегистрировать перехватчик вызовов и отфильтровать по типу триггера.

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

// Pre-invocation hook with trigger filtering
app.hook.preInvocation('httpPreInvocation', async (context) => {
  context.hookData.startTime = Date.now();
  context.invocationContext.log(`Pre-invocation hook executed for ${context.invocationContext.functionName}`);

  // Add custom headers or modify function handler if needed
  if (context.functionHandler.name === 'httpTrigger') {
    context.invocationContext.log('HTTP function detected, preparing request processing');
  }
}, {
  filter: ['httpTrigger']
});

// Post-invocation hook
app.hook.postInvocation('httpPostInvocation', async (context) => {
  const duration = Date.now() - context.hookData.startTime;
  context.invocationContext.log(`Function ${context.invocationContext.functionName} completed in ${duration}ms`);

  // Log results or errors
  if (context.error) {
    context.invocationContext.log.error(`Function failed: ${context.error.message}`);
  } else {
    context.invocationContext.log(`Function succeeded with result: ${JSON.stringify(context.result)}`);
  }
}, {
  filter: ['httpTrigger']
});

Первым аргументом обработчика хука является объект контекста, характерный для данного типа хуков.

Объект PreInvocationContext имеет следующие свойства.

Свойство Описание
inputs Аргументы, которые вы передаёте при вызове.
functionHandler Обработчик функции для вызова. Изменения этого значения влияют на саму функцию.
invocationContext Объект контекста вызова, переданный функции.
hookData Рекомендуемое место для хранения и совместного использования данных между перехватчиками в одной области. Используйте уникальное имя свойства, чтобы оно не конфликтовало с данными других хуков.

Объект PostInvocationContext имеет следующие свойства.

Свойство Описание
inputs Аргументы, которые ты передаёшь на призыв.
result Результат функции. Изменения этого значения влияют на общий результат функции.
error Ошибка, выбрасываемая функцией, или null/undefined, если ошибка отсутствует. Изменения этого значения влияют на общий результат функции.
invocationContext Объект контекста вызова, переданный функции.
hookData Рекомендуемое место для хранения и совместного использования данных между перехватчиками в одной области. Используйте уникальное имя свойства, чтобы оно не конфликтовало с данными других хуков.

Перехватчики приложений

Среда выполнения выполняет хуки приложения один раз для каждого экземпляра вашего приложения. Он выполняет хуки appStart при запуске и хуки appTerminate при завершении. Перехватчики завершения приложения (хуки) имеют ограниченное время выполнения и могут не выполняться во всех сценариях.

Среда выполнения Функции Azure в настоящее время не поддерживает логирование контекста вне вызова. Используйте пакет npm Application Insights для регистрации данных во время перехватчиков на уровне приложения.

В следующем примере регистрируются хуки приложений:

const { app } = require('@azure/functions');
const appInsights = require('applicationinsights');

// Initialize Application Insights for app-level logging
appInsights.setup().start();
const client = appInsights.defaultClient;

// App start hook
app.hook.appStart('appStartup', async (context) => {
  context.hookData.appStartTime = Date.now();
  context.hookData.initializationData = {};

  // Initialize shared resources, database connections, etc.
  client.trackEvent({
    name: 'FunctionAppStarted',
    properties: {
      timestamp: new Date().toISOString(),
      nodeVersion: process.version
    }
  });

  // Set up global configurations
  process.env.APP_INITIALIZED = 'true';
});

// App terminate hook
app.hook.appTerminate('appShutdown', async (context) => {
  const uptime = Date.now() - context.hookData.appStartTime;

  // Cleanup resources, close connections, etc.
  client.trackEvent({
    name: 'FunctionAppTerminated',
    properties: {
      uptime: uptime,
      timestamp: new Date().toISOString()
    }
  });

  // Flush Application Insights data
  await new Promise((resolve) => client.flush({ callback: resolve }));
});

Первым аргументом обработчика хука является объект контекста, характерный для данного типа хуков.

Объект AppStartContext обладает следующим свойством:

Свойство Описание
hookData Рекомендуемое место для хранения и совместного использования данных между перехватчиками в одной области. Используйте уникальное имя свойства, чтобы оно не конфликтовало с данными других хуков.

Объект AppTerminateContext обладает следующим свойством:

Свойство Описание
hookData Рекомендуемое место для хранения и совместного использования данных между перехватчиками в одной области. Используйте уникальное имя свойства, чтобы оно не конфликтовало с данными других хуков.

Лучшие практики использования хуков

При использовании хуков в Функции Azure учитывайте следующие рекомендации:

Вопросы производительности

  • Минимизируйте время выполнения хука, чтобы не влиять на производительность функций.
  • По возможности используйте асинхронные операции для предотвращения блокировки.
  • Учитывайте накладные расходы на хуки при обработке запросов с большим объёмом.

Обработка ошибок

  • Всегда предусматривайте в хуках корректную обработку ошибок.
  • Не позволяйте отказам крючка приводить к отказу функций, если это не абсолютно необходимо.
  • Ошибки hook следует регистрировать в журнале надлежащим образом для отладки.

Общий доступ к данным

  • Используйте hookData для обмена информацией между хуками до и после вызова.
  • Используйте уникальные имена свойств, чтобы избежать конфликтов с другими крючками.
  • Очищайте данные хука, когда они больше не нужны, чтобы предотвратить утечки памяти.

Фильтрация

  • Используйте фильтрацию типа триггеров, чтобы хуки выполнялись только для соответствующих функций.
  • Будьте конкретны в фильтрах для оптимизации производительности.

Масштабирование и параллелизм

По умолчанию Функции Azure автоматически отслеживает нагрузку в приложении и создает больше экземпляров узлов для Node.js по мере необходимости. Функции Azure использует встроенные (не настраиваемые пользователем) пороги для различных типов триггеров, чтобы решать, когда добавлять экземпляры, такие как возраст сообщений и размер очереди для QueueTrigger. Дополнительные сведения см. в статье, посвященной планам с оплатой по мере использования и планам "Премиум".

Такого поведения при масштабировании достаточно для многих приложений Node.js. Для приложений, зависящих от ЦП, производительность можно повысить путем увеличения числа рабочих процессов обработки языка. Число рабочих процессов на узел можно увеличить с 1 до максимума 10, используя параметр приложения FUNCTIONS_WORKER_PROCESS_COUNT. Функции Azure затем пытается равномерно распределять параллельные вызовы функций между этими рабочими. Такое поведение делает его менее вероятным, что функция с большим объемом ЦП блокирует выполнение других функций. Этот параметр применяется к каждому узлу, который Функции Azure создает при масштабировании приложения в соответствии с требованиями.

Предупреждение

FUNCTIONS_WORKER_PROCESS_COUNT Используйте параметр с осторожностью. Несколько процессов, выполняемых в одном экземпляре, могут привести к непредсказуемому поведению и увеличению времени загрузки функции. Если вы используете эту настройку, запуск из файла пакета может компенсировать эти недостатки.

Версия Node.js

Чтобы увидеть текущую версию, которую использует среда выполнения, можно выполнить логирование process.version из любой функции. Список supported versions версий Node.js, поддерживаемых каждой моделью программирования.

Настройка версии Node.js

Способ обновления версии Node.js зависит от ОС, на которой работает ваше приложение-функция.

Когда он запускается на Windows, настройте версию Node.js с помощью WEBSITE_NODE_DEFAULT_VERSION настройки приложения. Обновите этот параметр либо с помощью Azure CLI, либо в портале Azure.

Дополнительные сведения о версиях Node.js см. в статье "Поддерживаемые версии".

Перед обновлением версии Node.js убедитесь, что приложение-функция работает в последней версии среды выполнения Функции Azure. Если вам нужно обновить версию среды выполнения, ознакомьтесь с приложениями Migrate с Функции Azure версии 3.x до версии 4.x.

Выполните команду Azure CLI az functionapp config appsettings set, чтобы обновить версию Node.js приложения-функции, запущенную в Windows:

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

Эта команда устанавливает WEBSITE_NODE_DEFAULT_VERSION настройки приложения на поддерживаемую LTS-версию ~22.

После внесения изменений ваше приложение перезапускается. Дополнительные сведения о поддержке функций для Node.js см. в политике поддержки среды выполнения языка.

Переменные среды

Используйте переменные среды для управления операционными секретами, такими как строки соединений, ключи и конечные точки. Также используйте их для переменных окружения, например для переменных профиля. Добавляйте переменные среды как в локальной, так и в облачной среде и получайте доступ к process.env ним через ваш функциональный код.

В следующем примере регистрируется WEBSITE_SITE_NAME переменная среды:

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"]}`);
}

В локальной среде разработки

При локальном запуске проект функций содержит local.settings.json файл, в котором хранятся переменные среды в объекте Values .

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

В облачной среде Azure

При запуске в Azure приложение-функция позволяет задавать и использовать параметры Application, например строки подключения службы, и предоставляет эти параметры в качестве переменных среды во время выполнения.

Существует несколько способов для добавления, обновления и удаления параметров приложения-функции.

Изменения в настройках функционального приложения требуют его перезапуска.

Переменные рабочей среды

Node.js имеет несколько специфичных для него переменных среды Functions:

languageWorkers__node__arguments

Используйте эту настановку для указания пользовательских аргументов при запуске процесса Node.js. Чаще всего вы используете его локально для запуска рабочего в режиме отладки, но также можно использовать его в Azure, если нужны пользовательские аргументы.

Предупреждение

Если возможно, избегайте использования languageWorkers__node__arguments в Azure, так как это может негативно повлиять на время холодного запуска. Вместо использования предварительно запущенных рабочих процессов среде выполнения приходится запускать новый рабочий процесс с нуля, используя ваши аргументы.

ЛогированиеlogLevelWorker

Используйте этот параметр, чтобы настроить уровень журналирования по умолчанию для журналов worker-процессов Node.js. По умолчанию отображаются только журналы предупреждений или ошибок, но вы можете настроить это на information или debug, чтобы помочь диагностировать проблемы с работником Node.js. Дополнительные сведения см. в разделе Настройка уровней журнала.

Модули ECMAScript (предварительная версия)

Примечание.

Модули ECMAScript в настоящее время являются предпросмотрной функцией в Node.js 14 и выше в Функции Azure.

Модули ECMAScript (модули ES) — это новая официальная стандартная система модулей для Node.js. Пока что в примерах кода в этой статье используется синтаксис CommonJS. При запуске Функции Azure в Node.js 14 или выше вы можете выбрать написание функций, используя синтаксис модулей ES.

Чтобы использовать в функции модули ES, переименуйте ее файл, заменив расширение на .mjs. Следующий пример файла index.mjs — это функция, активируемая через HTTP, которая использует синтаксис модулей ES для импорта библиотеки uuid и возвращает значение.

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,
});

Настройка точки входа функции

Используйте function.json свойства scriptFile и entryPoint чтобы задать местоположение и название экспортируемой функции. Когда вы используете TypeScript, вам нужно это scriptFile свойство, и оно должно указывать на скомпилированный JavaScript.

С использованием scriptFile

По умолчанию функция JavaScript выполняется из index.js. Этот файл использует тот же родительский каталог, что и соответствующий function.json файл.

Используйте scriptFile для организации структуры папок. Следующий пример показывает один из способов настройки ваших папок:

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

Файл function.json для myFirstFunction должен содержать scriptFile свойство, указывающее на файл с экспортированной функцией для запуска.

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

С использованием entryPoint

В модели v3 необходимо экспортировать функцию с помощью module.exports, чтобы её можно было найти и запустить. По умолчанию функция, которая запускается при срабатывании, является единственным экспортом из этого файла. Это также может быть экспортное имя run или экспорт с названием index. В следующем примере устанавливается entryPoint в function.json на настраиваемое значение "logHello":

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

module.exports = { logHello };

Рекомендации

В этом разделе описаны несколько важных шаблонов для Node.js приложений, которым стоит следовать.

Выбирайте планы службы приложений с одним vCPU

Когда вы создаёте функциональное приложение, использующее тарифный план App Service, выберите план с одним vCPU, а не план с несколькими vCPU. Сегодня Functions эффективнее выполняет функции Node.js на виртуальных машинах с одним vCPU, а использование виртуальных машин большего размера не дает ожидаемого прироста производительности. При необходимости можно масштабироваться, добавляя больше экземпляров виртуальных машин с одним процессором, или включить автомасштабирование. Дополнительные сведения см. в статье Масштабирование числа экземпляров вручную или автоматически.

Запуск из файла пакета

При разработке Функции Azure в бессерверной модели размещения холодные запуски являются реальностью. Холодный запуск обозначает первый запуск функции приложения после периода простоя, что требует больше времени на включение. Для приложений Node.js с большими деревьями зависимостей холодный старт может иметь значительное влияние. Чтобы ускорить процесс холодного запуска, по возможности выполняйте функции в виде файла пакета. Во многих методах развертывания этот вариант используется по умолчанию, но если вы сталкиваетесь с длительным холодным стартом, убедитесь, что используете именно его.

Использование async и await

При написании функций Azure на Node.js пишите код с использованием ключевых слов async и await. Написание кода с использованием async и await вместо обратных вызовов или .then и .catch при использовании промисов помогает избежать двух распространённых проблем:

  • Возникновение неперехваченных исключений, которые приводят к аварийному завершению процесса Node.js, что может повлиять и на выполнение других функций.
  • Непредвиденное поведение, например отсутствие журналов из context.log, вызванное асинхронными вызовами, которые не ожидаются должным образом.

В следующем примере асинхронный метод fs.readFile вызывается с функцией обратного вызова error-first в качестве второго параметра. Этот код вызывает обе проблемы, упомянутые ранее. Исключение, которое намеренно не обработано в нужной области, может обрушить весь процесс (проблема №1). Возврат без завершения обратного вызова приводит к тому, что HTTP-ответ иногда имеет пустое тело (проблема #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 };
    },
});

В следующем примере асинхронный метод fs.readFile вызывается с функцией обратного вызова error-first в качестве второго параметра. Этот код вызывает обе вышеупомянутые проблемы. Исключение, которое явно не попадает в правильную область действия, может вызвать сбой всего процесса (проблема #1). Вызов устареваемого context.done() метода вне сферы действия обратного вызова может сигнализировать о завершении функции до того, как файл будет прочитан (проблема #2). В этом примере слишком ранний вызов context.done() приводит к отсутствию записей в журнале, начиная с 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();
};

Используйте async ключевые слова и await , чтобы избежать обеих этих проблем. Большинство API в экосистеме Node.js теперь поддерживают обещания в той или иной форме. Например, начиная с версии 14, Node.js предоставляет fs/promises API для замены fs API обратного вызова.

В следующем примере любые необработанные исключения, вызываемые во время выполнения функции, приводят к сбою только отдельного вызова, вызвавшего исключение. Ключевое await слово означает, что шаги, следующие за readFile, выполняются только после его завершения.

// 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;
        }
    },
});

Когда вы используете async и await, вам не нужно вызывать 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}`);
};

Устранение неполадок

См. руководство по устранению неполадок Node.js.

Следующие шаги

Дополнительные сведения см. на следующих ресурсах: