Использование пакета SDK WebJobs Azure для фоновой обработки на основе событий

В этой статье приводятся рекомендации по работе с пакетом SDK для веб-заданий Azure. Инструкции по началу работы см. в статье Начало работы с пакетом SDK для веб-заданий Azure.

Версии пакета SDK для веб-заданий

Это ключевые различия между версией 3.x и версией 2.x пакета SDK для веб-заданий.

  • В версии 3.x добавлена поддержка .NET Core.
  • В версии 3.x необходимо устанавливать расширения привязки хранилища, которые являются обязательными для пакета SDK веб-заданий. В версии 2.x привязки хранилища включены в пакет SDK.
  • Инструментарий, используемый в Visual Studio 2019 для проектов .NET Core (3.x), отличается от инструментов для проектов .NET Framework (2.x). Дополнительные сведения см. в разделе Разработка и развертывание веб-заданий в Службе приложений Azure с помощью Visual Studio.

Некоторые описания в этой статье содержат примеры для веб-заданий версий как 3.x, так и 2.x.

Функции Azure используют пакет SDK веб-заданий.

  • Функции Azure версии 2.x используют пакет SDK веб-заданий версии 3.x.
  • Функции Azure версии 1.x используют пакет SDK веб-заданий версии 2.x.

В репозиториях исходного кода как для Функций Azure, так и для пакета SDK веб-заданий используется нумерация пакетов SDK для веб-заданий. Некоторые разделы этой статьи содержат ссылки на документацию по Функциям Azure.

Дополнительные сведения см. в статье Сравнение пакета SDK веб-заданий и Функций Azure.

Узел веб-заданий

Узел — это контейнер среды выполнения для функций. Он прослушивает триггеры и вызовы функций. В версии 3.x узел является реализацией IHost. В версии 2.x используется объект JobHost. Вам нужно создать экземпляр узла в коде и написать код, чтобы настроить его работу.

Этим работа напрямую с пакетом SDK для веб-заданий отличается от работы с использованием решения "Функции Azure". В решении "Функции Azure" эта служба управляет узлом и ее нельзя настроить путем написания кода. Это решение позволяет настроить поведение узла с помощью настроек в файле host.json. Эти параметры представляют собой строки, а не код, что ограничивает диапазон их применения для настройки.

Строки подключения узла

Пакет SDK для веб-заданий ищет строки подключения служебной шины Azure и службы хранилища Azure в файле local.settings.json при локальном запуске или в среде веб-заданий при запуске в Azure. По умолчанию пакету SDK для веб-заданий требуется параметр строки подключения к хранилищу под именем AzureWebJobsStorage.

Версия 2.x пакета SDK не требует определенного имени. Версия 2.x пакета SDK позволяет использовать собственные имена для этих строк подключения или хранить их в другом месте. Вы можете задать имена в коде с помощью JobHostConfiguration, как показано ниже.

static void Main(string[] args)
{
    var _storageConn = ConfigurationManager
        .ConnectionStrings["MyStorageConnection"].ConnectionString;

    //// Dashboard logging is deprecated; use Application Insights.
    //var _dashboardConn = ConfigurationManager
    //    .ConnectionStrings["MyDashboardConnection"].ConnectionString;

    JobHostConfiguration config = new JobHostConfiguration();
    config.StorageConnectionString = _storageConn;
    //config.DashboardConnectionString = _dashboardConn;
    JobHost host = new JobHost(config);
    host.RunAndBlock();
}

Примечание

Так как он использует API конфигурации .NET Core по умолчанию, в версии 3.x отсутствует API для изменения имен строк подключения. См. статью Разработка и развертывание веб-заданий с использованием Visual Studio.

Параметры разработки узла

Вы можете запустить узел в режиме разработки, чтобы повысить эффективность локальной разработки. Ниже приведены некоторые параметры, которые автоматически изменяются в режиме разработки.

Свойство Параметр разработки
Tracing.ConsoleLevel TraceLevel.Verbose — чтобы увеличить выходные данные журнала.
Queues.MaxPollingInterval Низкое значение для обеспечения немедленного запуска методов очереди.
Singleton.ListenerLockPeriod 15 секунд для ускорения последовательной разработки.

Способ включения режима разработки зависит от версии пакета SDK.

Версия 3.x

Версия 3.x использует стандартные API ASP.NET Core. Вызовите метод UseEnvironment в экземпляре HostBuilder. Передайте строку с именем development, как показано в следующем примере.

static async Task Main()
{
    var builder = new HostBuilder();
    builder.UseEnvironment("development");
    builder.ConfigureWebJobs(b =>
            {
                b.AddAzureStorageCoreServices();
            });
    var host = builder.Build();
    using (host)
    {
        await host.RunAsync();
    }
}

Версия 2.x

В классе JobHostConfiguration имеется метод UseDevelopmentSettings, который включает режим разработки. В следующем примере показано, как использовать параметры разработки. Чтобы config.IsDevelopment возвращал значение true при локальном запуске, установите локальную переменную среды AzureWebJobsEnv со значением Development.

static void Main()
{
    config = new JobHostConfiguration();

    if (config.IsDevelopment)
    {
        config.UseDevelopmentSettings();
    }

    var host = new JobHost(config);
    host.RunAndBlock();
}

Управление одновременными подключениями (версия 2.x)

В версии 3.x ограничение числа подключений сбрасывается к значению по умолчанию (бесконечное число подключений). Если по какой-либо причине необходимо изменить это ограничение, вы можете использовать свойство MaxConnectionsPerServer класса WinHttpHandler.

В версии 2.x вы контролируете количество одновременных подключений к узлу с помощью API-интерфейса ServicePointManager.DefaultConnectionLimit. В версии 2.x перед запуском узла веб-заданий необходимо увеличить это значение со значения по умолчанию 2.

Все исходящие HTTP-запросы, выполняемые из функции, используя HttpClient, проходят через ServicePointManager. Когда достигается значение, установленное в DefaultConnectionLimit, ServicePointManager начинает добавлять запросы в очередь перед их отправкой. Предположим, что для ограничения DefaultConnectionLimit установлено значение 2 и код включает 1000 HTTP-запросов. Первоначально в ОС разрешено только два запроса. Остальные 998 поставлены в очередь, пока не появится место для них. Это означает, что может истечь время ожидания HttpClient, потому что считается, что запрос выполнен, но на самом деле он никогда не отправлялся ОС на целевой сервер. Таким образом, вы можете столкнуться с поведением, которое не имеет смысла: локальному клиенту HttpClient потребуется 10 секунд, чтобы выполнить запрос, но служба будет возвращать каждый запрос за 200 мс.

Значение по умолчанию для приложений ASP.NET — Int32.MaxValue, и это, вероятно, эффективно для веб-заданий, запущенных в базовом плане службы приложений или плане более высокого уровня. Веб-заданиям обычно требуется параметр Always On, который поддерживается только базовыми планами службы приложений или планами более высокого уровня.

Если ваше задание WebJob работает в бесплатном или общем плане службы приложений, приложение ограничено песочницей службы приложений, которая в настоящее время имеет такое ограничение подключений — 300. При неограниченном подключении в ServicePointManager более вероятно, что будет достигнут порог подключения песочницы, а сайт отключится. В этом случае установка более низкого значения параметра DefaultConnectionLimit, например 50 или 100, может не допустить события выше и обеспечить достаточную пропускную способность.

Параметр нужно настроить перед выполнением HTTP-запросов. По этой причине узел веб-заданий не должен настраивать параметр автоматически. HTTP-запросы могут выполняться перед запуском узла, что может привести к непредвиденному поведению. Оптимальный подход — сразу же установить значение в методе Main перед инициализацией JobHost, как показано в следующем примере.

static void Main(string[] args)
{
    // Set this immediately so that it's used by all requests.
    ServicePointManager.DefaultConnectionLimit = Int32.MaxValue;

    var host = new JobHost();
    host.RunAndBlock();
}

Триггеры

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

Функции должны быть общедоступными методами и иметь один атрибут триггера или атрибут NoAutomaticTrigger.

Автоматические триггеры

Автоматические триггеры вызывают функцию в ответ на событие. Рассмотрим этот пример функции, которая запускается сообщением, добавленным в хранилище очередей Azure. Она реагирует на считывание BLOB-объекта из хранилища BLOB-объектов Azure.

public static void Run(
    [QueueTrigger("myqueue-items")] string myQueueItem,
    [Blob("samples-workitems/{queueTrigger}", FileAccess.Read)] Stream myBlob,
    ILogger log)
{
    log.LogInformation($"BlobInput processed blob\n Name:{myQueueItem} \n Size: {myBlob.Length} bytes");
}

Например, атрибут QueueTrigger вызывает в среде выполнения функцию всякий раз, когда в очереди myqueue-items появляется очередное сообщение. Атрибут Blob вынуждает среду выполнения использовать сообщение из очереди для чтения большого двоичного объекта из контейнера sample-workitems. Имя элемента BLOB-объекта в контейнере samples-workitems получено непосредственно от триггера очереди как выражение привязки ({queueTrigger}).

Примечание

Время ожидания веб-приложения может истечь через 20 минут бездействия, и только запросы к реальному веб-приложению могут сбросить таймер. Таймер не будет сброшен при просмотре конфигурации приложения на портале Azure или выполнении запросов к сайту расширенных средств (https://<app_name>.scm.azurewebsites.net). Если веб-приложение, в котором размещено ваше задание, настроено для выполнения непрерывных или запланированных заданий либо использования триггеров на основе событий, установите параметр Всегда включено в Azure на странице Конфигурация веб-приложения. Этот параметр позволяет гарантировать, что такие типы веб-заданий будут надежно выполняться. Эта функция доступна только в ценовых категориях "Базовый", "Стандартный" и "Премиум".

Ручные триггеры

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

[NoAutomaticTrigger]
public static void CreateQueueMessage(
ILogger logger,
string value,
[Queue("outputqueue")] out string message)
{
    message = value;
    logger.LogInformation("Creating queue message: ", message);
}

Процесс запуска функции вручную зависит от версии пакета SDK.

Версия 3.x

static async Task Main(string[] args)
{
    var builder = new HostBuilder();
    builder.ConfigureWebJobs(b =>
    {
        b.AddAzureStorageCoreServices();
        b.AddAzureStorage();
    });
    var host = builder.Build();
    using (host)
    {
        var jobHost = host.Services.GetService(typeof(IJobHost)) as JobHost;
        var inputs = new Dictionary<string, object>
        {
            { "value", "Hello world!" }
        };

        await host.StartAsync();
        await jobHost.CallAsync("CreateQueueMessage", inputs);
        await host.StopAsync();
    }
}

Версия 2.x

static void Main(string[] args)
{
    JobHost host = new JobHost();
    host.Call(typeof(Program).GetMethod("CreateQueueMessage"), new { value = "Hello world!" });
}

Входные и выходные привязки

Входные привязки предоставляют декларативный способ получения данных для кода из внешних служб или служб Azure. Выходные привязки обеспечивают способ обновления данных. Примеры привязок приводятся в статье Начало работы.

Возвращаемое значение метода можно использовать для привязки выходных данных. Для этого примените атрибут к возвращаемому значению метода. См. пример в разделе Использование возвращаемого значения решения "Функции Azure".

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

Процесс установки и управления типами привязок зависит от того, используете ли вы версию 3.x или 2.x пакета SDK. Вы можете найти пакет, устанавливаемый для определенного типа привязки, в разделе "Пакеты" справочной статьи для соответствующего типа привязки для решения "Функции Azure". Исключением является триггер и привязка файлов (для локальной файловой системы), которая не поддерживается решением "Функции Azure".

Версия 3.x

В версии 3.x привязки хранилища включены в пакет Microsoft.Azure.WebJobs.Extensions.Storage. Вызовите метод расширения AddAzureStorage в методе ConfigureWebJobs, как показано далее.

static async Task Main()
{
    var builder = new HostBuilder();
    builder.ConfigureWebJobs(b =>
            {
                b.AddAzureStorageCoreServices();
                b.AddAzureStorage();
            });
    var host = builder.Build();
    using (host)
    {
        await host.RunAsync();
    }
}

Чтобы использовать другие типы триггеров и привязок, установите пакет NuGet, который их содержит, и вызовите метод расширения Add<binding>, реализованный в расширении. Например, если вы хотите использовать привязку Azure Cosmos DB, установите Microsoft.Azure.WebJobs.Extensions.CosmosDB и вызовите AddCosmosDB, как показано далее.

static async Task Main()
{
    var builder = new HostBuilder();
    builder.ConfigureWebJobs(b =>
            {
                b.AddAzureStorageCoreServices();
                b.AddCosmosDB();
            });
    var host = builder.Build();
    using (host)
    {
        await host.RunAsync();
    }
}

Чтобы использовать триггер таймера или привязку файлов, являющиеся частью основных служб, вызовите методы расширения AddTimers или AddFiles.

Версия 2.x

В пакет версии 2. xMicrosoft.Azure.WebJobs включены следующие типы триггеров и привязок.

  • Хранилище BLOB-объектов
  • Хранилище очередей
  • Хранилище таблиц

Чтобы использовать другие типы триггеров и привязок, установите пакет NuGet, который их содержит, и вызовите метод Use<binding> для объекта JobHostConfiguration. Например, если вы хотите использовать триггер таймера, установите Microsoft.Azure.WebJobs.Extensions и вызовите UseTimers в методе Main, как показано далее.

static void Main()
{
    config = new JobHostConfiguration();
    config.UseTimers();
    var host = new JobHost(config);
    host.RunAndBlock();
}

Чтобы использовать привязку файлов, установите Microsoft.Azure.WebJobs.Extensions и вызовите UseFiles.

ExecutionContext

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

public class Functions
{
    public static void ProcessQueueMessage([QueueTrigger("queue")] string message,
        ExecutionContext executionContext,
        ILogger logger)
    {
        logger.LogInformation($"{message}\n{executionContext.InvocationId}");
    }
}

Процесс привязки к ExecutionContext зависит от версии пакета SDK.

Версия 3.x

Вызовите метод расширения AddExecutionContextBinding в методе ConfigureWebJobs, как показано далее.

static async Task Main()
{
    var builder = new HostBuilder();
    builder.ConfigureWebJobs(b =>
            {
                b.AddAzureStorageCoreServices();
                b.AddExecutionContextBinding();
            });
    var host = builder.Build();
    using (host)
    {
        await host.RunAsync();
    }
}

Версия 2.x

Пакет Microsoft.Azure.WebJobs.Extensions, упомянутый ранее, также предоставляет специальный тип привязки, который вы можете зарегистрировать, вызвав метод UseCore. Эта привязка позволяет определить параметр ExecutionContext в сигнатуре функции, который включается следующим образом.

class Program
{
    static void Main()
    {
        config = new JobHostConfiguration();
        config.UseCore();
        var host = new JobHost(config);
        host.RunAndBlock();
    }
}

Конфигурация привязки

Можно настроить поведение некоторых триггеров и привязок. Процесс настройки зависит от версии пакета SDK.

  • Версия 3.x: конфигурация настраивается при вызове метода Add<Binding> в ConfigureWebJobs.
  • Версия 2.x: конфигурация настраивается путем настройки свойств в объекте конфигурации, который передается в JobHost.

Эти зависимые от привязки параметры эквивалентны параметрам в файле проекта host.json в решении "Функции Azure".

Можно настроить следующие привязки.

Конфигурация триггера Azure Cosmos DB (версия 3.x)

В этом примере показано, как настраивать и просматривать журналы триггеров Azure Cosmos DB.

static async Task Main()
{
    var builder = new HostBuilder();
    builder.ConfigureWebJobs(b =>
    {
        b.AddAzureStorageCoreServices();
        b.AddCosmosDB(a =>
        {
            a.ConnectionMode = ConnectionMode.Gateway;
            a.Protocol = Protocol.Https;
            a.LeaseOptions.LeasePrefix = "prefix1";

        });
    });
    var host = builder.Build();
    using (host)
    {
        await host.RunAsync();
    }
}

Дополнительные сведения см. в статье о привязке Azure Cosmos DB .

Конфигурация триггеров Центров событий (версия 3.x)

В этом примере показано, как настроить триггер Центров событий.

static async Task Main()
{
    var builder = new HostBuilder();
    builder.ConfigureWebJobs(b =>
    {
        b.AddAzureStorageCoreServices();
        b.AddEventHubs(a =>
        {
            a.BatchCheckpointFrequency = 5;
            a.EventProcessorOptions.MaxBatchSize = 256;
            a.EventProcessorOptions.PrefetchCount = 512;
        });
    });
    var host = builder.Build();
    using (host)
    {
        await host.RunAsync();
    }
}

Дополнительные сведения см. в статье о привязке Центров событий.

Конфигурация триггера хранилища очередей

В примерах ниже показано, как настроить триггер Хранилища очередей.

Версия 3.x

static async Task Main()
{
    var builder = new HostBuilder();
    builder.ConfigureWebJobs(b =>
    {
        b.AddAzureStorageCoreServices();
        b.AddAzureStorage(a => {
            a.BatchSize = 8;
            a.NewBatchThreshold = 4;
            a.MaxDequeueCount = 4;
            a.MaxPollingInterval = TimeSpan.FromSeconds(15);
        });
    });
    var host = builder.Build();
    using (host)
    {
        await host.RunAsync();
    }
}

Дополнительные сведения см. в статье о привязке Хранилища очередей.

Версия 2.x

static void Main(string[] args)
{
    JobHostConfiguration config = new JobHostConfiguration();
    config.Queues.BatchSize = 8;
    config.Queues.NewBatchThreshold = 4;
    config.Queues.MaxDequeueCount = 4;
    config.Queues.MaxPollingInterval = TimeSpan.FromSeconds(15);
    JobHost host = new JobHost(config);
    host.RunAndBlock();
}

Дополнительные сведения см. в справочной статье о host.json версии 1.x.

Настройка привязки SendGrid (версия 3.x)

В этом примере показано, как настроить привязку выходных данных SendGrid.

static async Task Main()
{
    var builder = new HostBuilder();
    builder.ConfigureWebJobs(b =>
    {
        b.AddAzureStorageCoreServices();
        b.AddSendGrid(a =>
        {
            a.FromAddress.Email = "samples@functions.com";
            a.FromAddress.Name = "Azure Functions";
        });
    });
    var host = builder.Build();
    using (host)
    {
        await host.RunAsync();
    }
}

Дополнительные сведения см. в статье о привязке SendGrid.

Настройка триггера служебной шины (версия 3.x)

В этом примере показано, как настроить триггер служебной шины.

static async Task Main()
{
    var builder = new HostBuilder();
    builder.ConfigureWebJobs(b =>
    {
        b.AddAzureStorageCoreServices();
        b.AddServiceBus(sbOptions =>
        {
            sbOptions.MessageHandlerOptions.AutoComplete = true;
            sbOptions.MessageHandlerOptions.MaxConcurrentCalls = 16;
        });
    });
    var host = builder.Build();
    using (host)
    {
        await host.RunAsync();
    }
}

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

Конфигурация для других привязок

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

Версия 3.x

static async Task Main()
{
    var builder = new HostBuilder();
    builder.ConfigureWebJobs(b =>
    {
        b.AddAzureStorageCoreServices();
        b.AddFiles(a => a.RootPath = @"c:\data\import");
    });
    var host = builder.Build();
    using (host)
    {
        await host.RunAsync();
    }
}

Версия 2.x

static void Main()
{
    config = new JobHostConfiguration();
    var filesConfig = new FilesConfiguration
    {
        RootPath = @"c:\data\import"
    };
    config.UseFiles(filesConfig);
    var host = new JobHost(config);
    host.RunAndBlock();
}

Выражения привязки

В параметрах конструктора атрибутов вы можете использовать выражения, которые разрешают значения из разных источников. Например, в следующем коде путь для атрибута BlobTrigger создает выражение с именем filename. При использовании для выходной привязки filename разрешается к имени активирующего большого двоичного объекта.

public static void CreateThumbnail(
    [BlobTrigger("sample-images/{filename}")] Stream image,
    [Blob("sample-images-sm/{filename}", FileAccess.Write)] Stream imageSmall,
    string filename,
    ILogger logger)
{
    logger.Info($"Blob trigger processing: {filename}");
    // ...
}

Дополнительные сведения о выражениях привязки см. в разделе Выражения привязки и шаблоны в документации по решению "Функции Azure".

Настраиваемые выражения привязки

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

Это можно сделать, передав пользовательский сопоставитель имен во время настройки. Заполнители включаются в параметры конструктора триггера или атрибута привязки, а код сопоставителя предоставляет фактические значения, которые будут использоваться вместо этих заполнителей. Вы определяете заполнители, заключив их в знаки процента (%), как показано ниже.

public static void WriteLog([QueueTrigger("%logqueue%")] string logMessage)
{
    Console.WriteLine(logMessage);
}

Этот код позволяет использовать очередь с именем logqueuetest в тестовой среде и очередь с именем logqueueprod в производственной среде. Вместо фиксированного имени очереди требуется указать имя записи в коллекции appSettings.

Существует сопоставитель по умолчанию, который вступает в силу, если вы не предоставляете настраиваемый. Стандартное средство получает значения из настроек приложения или переменных среды.

Начиная с .NET Core 3.1, ConfigurationManager для использования требуется пакет NuGet System.Configuration.ConfigurationManager. Для примера требуется следующая using инструкция:

using System.Configuration;

Класс NameResolver получает имя очереди из параметров приложения, как показано ниже:

public class CustomNameResolver : INameResolver
{
    public string Resolve(string name)
    {
        return ConfigurationManager.AppSettings[name].ToString();
    }
}

Версия 3.x

Распознаватель настраивается путем добавления зависимостей. Для этих примеров необходим следующий оператор using:

using Microsoft.Extensions.DependencyInjection;

Сопоставитель добавляется путем вызова метода расширения ConfigureServices в HostBuilder, как показано в этом примере:

static async Task Main(string[] args)
{
    var builder = new HostBuilder();
    var resolver = new CustomNameResolver();
    builder.ConfigureWebJobs(b =>
    {
        b.AddAzureStorageCoreServices();
    });
    builder.ConfigureServices(s => s.AddSingleton<INameResolver>(resolver));
    var host = builder.Build();
    using (host)
    {
        await host.RunAsync();
    }
}

Версия 2.x

Передайте класс NameResolver в объект JobHost, как показано ниже.

 static void Main(string[] args)
{
    JobHostConfiguration config = new JobHostConfiguration();
    config.NameResolver = new CustomNameResolver();
    JobHost host = new JobHost(config);
    host.RunAndBlock();
}

Решение "Функции Azure" реализует INameResolver, чтобы получить значения из настроек приложения, как показано в этом примере. Когда вы используете пакет SDK WebJobs напрямую, вы можете написать специальную реализацию, которая получает значения замены заполнителя из любого выбранного источника.

Привязка во время выполнения

Если перед использованием атрибута привязки для веб-заданий, например Queue, Blob или Table, необходимо выполнить какие-либо действия с функцией, можно использовать интерфейс IBinder.

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

public static void CreateQueueMessage(
    [QueueTrigger("inputqueue")] string queueMessage,
    IBinder binder)
{
    string outputQueueName = "outputqueue" + DateTime.Now.Month.ToString();
    QueueAttribute queueAttribute = new QueueAttribute(outputQueueName);
    CloudQueue outputQueue = binder.Bind<CloudQueue>(queueAttribute);
    outputQueue.AddMessageAsync(new CloudQueueMessage(queueMessage));
}

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

Справочная информация о привязке

В документации по решению "Функции Azure" содержится справочная информация о каждом типе привязки. В каждой справочной статье о привязке вы найдете следующие сведения. (Этот пример учитывает очередь хранилища.)

  • Пакеты. Сведения о том, какой пакет установить, чтобы включить поддержку привязки в проекте пакета SDK для веб-заданий.
  • Примеры. Примеры кода. Пример библиотеки классов C# применяется к пакету SDK для веб-заданий. Просто опустите атрибут FunctionName.
  • Атрибуты. Атрибуты, используемые для типа привязки.
  • Конфигурация. Объяснения свойств атрибута и параметров конструктора.
  • Использование. Сведения о том, к каким типам можно применить привязку и как она работает. Например: алгоритм опроса, обработка подозрительной очереди.

Примечание

Привязки HTTP, веб-перехватчика и службы "Сетка событий" поддерживаются только с помощью решения "Функции Azure", а не пакета SDK для веб-заданий.

Полный список привязок, поддерживаемых в среде выполнения функций Azure, см. в статье Поддерживаемые привязки.

Атрибуты для отключения, времени ожидания и отдельного выполнения

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

Атрибут Disable

Атрибут Disable позволяет управлять запуском функции.

В следующем примере, если параметр приложения Disable_TestJob имеет значение 1 или True (без учета регистра), функция не запускается. В этом случае среда выполнения создает сообщение журнала о том, что функция Functions.TestJob отключена.

[Disable("Disable_TestJob")]
public static void TestJob([QueueTrigger("testqueue2")] string message)
{
    Console.WriteLine("Function with Disable attribute executed!");
}

Когда вы изменяете значения параметра приложения на портале Azure, нужно повторно запустить веб-задание с помощью нового параметра.

Атрибут может объявляться на уровне класса, метода или параметра. Имя параметра также может содержать выражения привязки.

Атрибут Timeout

Атрибут Timeout требует отмены функции, если она не завершена в течение определенного периода времени. В следующем примере функция будет работать в течение одного дня без использования атрибута Timeout. При использовании атрибута Timeout функция будет отменена через 15 секунд. Если параметру throwOnError атрибута Timeout присвоено значение true, вызов функции завершается тем, что пакет SDK веб-заданий создает исключение при превышении интервала ожидания. По умолчанию для throwOnError используется значение false. Если используется атрибут Timeout, по умолчанию вызов функции будет отменяться путем установки маркера отмены. При этом вызов будет выполняться бесконечно, пока код функции не вернет или не вызовет исключение.

[Timeout("00:00:15")]
public static async Task TimeoutJob(
    [QueueTrigger("testqueue2")] string message,
    CancellationToken token,
    TextWriter log)
{
    await log.WriteLineAsync("Job starting");
    await Task.Delay(TimeSpan.FromDays(1), token);
    await log.WriteLineAsync("Job completed");
}

Вы можете применить атрибут Timeout на уровне класса или метода и указать глобальное время ожидания, используя JobHostConfiguration.FunctionTimeout. Время ожидания на уровне класса или метода переопределяет глобальное время ожидания.

Атрибут Singleton

Используйте атрибут Singleton, чтобы обеспечить выполнение только одного экземпляра функции даже при наличии нескольких экземпляров несущего веб-приложения. Атрибут Singleton (Отдельное выполнение) использует распределенную блокировку, чтобы гарантировать выполнение только одного экземпляра.

В этом примере только один экземпляр функции ProcessImage запускается в любой момент времени.

[Singleton]
public static async Task ProcessImage([BlobTrigger("images")] Stream image)
{
     // Process the image.
}

SingletonMode.Listener

У некоторых триггеров есть встроенная поддержка для управления параллелизмом:

  • QueueTrigger. Присвойте параметру JobHostConfiguration.Queues.BatchSize значение 1.
  • ServiceBusTrigger. Присвойте параметру ServiceBusConfiguration.MessageOptions.MaxConcurrentCalls значение 1.
  • FileTrigger. Присвойте параметру FileProcessor.MaxDegreeOfParallelism значение 1.

Эти параметры можно использовать для обеспечения отдельного выполнения функции в одном экземпляре. Чтобы гарантировать, что запущен только один экземпляр функции, если веб-приложение масштабируется до нескольких экземпляров, примените блокировку Singleton для уровня прослушивателя в функции ([Singleton(Mode = SingletonMode.Listener)]). Блокировки прослушивателя инициируются при запуске узла JobHost. Если все три горизонтально масштабированные экземпляры запускаются одновременно, блокировки требует только один из экземпляров, а запускается только один прослушиватель.

Примечание

Дополнительные сведения о работе SingletonMode.Function см. в этом репозитории GitHub.

Значения области

Можно указать выражение или значение области для атрибута Singleton. Это выражение/значение гарантирует, что все выполнения функции в определенной области будут сериализованы. Реализация более специализированной блокировки может обеспечить некоторый уровень параллелизма функции при сохранении сериализации других вызовов соответственно с вашими требованиями. В следующем коде рассматриваются привязки выражения области к значению Region входящего сообщения. Когда очередь содержит три сообщения в регионах "Восток", "Восток" и "Запад", тогда сообщения с регионом "Восток" выполняются последовательно, в то время как сообщение с регионом "Запад" выполняется параллельно с сообщениями региона "Восток".

[Singleton("{Region}")]
public static async Task ProcessWorkItem([QueueTrigger("workitems")] WorkItem workItem)
{
     // Process the work item.
}

public class WorkItem
{
     public int ID { get; set; }
     public string Region { get; set; }
     public int Category { get; set; }
     public string Description { get; set; }
}

SingletonScope.Host

Областью по умолчанию для блокировки является SingletonScope.Function. Это означает, что область блокировки (путь аренды большого двоичного объекта) привязана к полному имени функции. Чтобы заблокировать функции, укажите узел SingletonScope.Host и используйте имя идентификатора области, одинаковое для всех функций, которые не нужно запускать одновременно. В следующем примере выполняется только один экземпляр AddItem или RemoveItem:

[Singleton("ItemsLock", SingletonScope.Host)]
public static void AddItem([QueueTrigger("add-item")] string message)
{
     // Perform the add operation.
}

[Singleton("ItemsLock", SingletonScope.Host)]
public static void RemoveItem([QueueTrigger("remove-item")] string message)
{
     // Perform the remove operation.
}

Просмотр арендуемых больших двоичных объектов

Пакет SDK WebJobs использует аренды больших двоичных объектов Azure для реализации распределенной блокировки. Арендуемые большие двоичные объекты, используемые Singleton, можно найти в контейнере azure-webjobs-host в учетной записи хранения AzureWebJobsStorage по пути locks. Например, путь к арендуемому большому двоичному объекту для первого примера ProcessImage, рассмотренного ранее, должен быть таким: locks/061851c758f04938a4426aa9ab3869c0/WebJobs.Functions.ProcessImage. Все пути включают идентификатор JobHost, в данном случае 061851c758f04938a4426aa9ab3869c0.

Асинхронные функции

Информацию о том, как закодировать асинхронные функции, см. в документации по решению "Функции Azure".

Токены отмены

Информацию о том, как обрабатывать маркеры отмены, см. в документации по решению "Функции Azure" в разделе Токены отмены.

Несколько экземпляров

Если ваше веб-приложение работает в нескольких экземплярах, на каждом экземпляре запускается непрерывный WebJob, который прослушивает триггеры и вызывает функции. Различные привязки триггера предназначены для эффективной совместной работы в экземплярах, чтобы масштабирование до большего количества экземпляров позволяло обрабатывать большую нагрузку.

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

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

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

Фильтры

Функциональные фильтры (предварительная версия) обеспечивают способ настройки конвейера выполнения WebJobs с помощью вашей собственной логики. Фильтры сходны с фильтрами ASP.NET Core. Их можно реализовать как декларативные атрибуты, которые применяются к функциям или классам. Дополнительные сведения см. на странице о фильтрах функции.

Ведение журналов и мониторинг

Мы рекомендуем использовать платформу журналирования, разработанную для ASP.NET. В статье Начало работы показано, как используется эта платформа.

Фильтрация журнала

Каждый журнал, созданный экземпляром ILogger, имеет связанные параметры Category и Level. Параметр LogLevel является перечислением целочисленных значений, которые обозначают относительную важность.

LogLevel Код
Трассировка 0
Отладка 1
Сведения 2
Предупреждение 3
Error 4
Critical 5
None 6

Каждую категорию можно независимо отфильтровать в соответствии с определенным LogLevel. Например, вы можете просмотреть все журналы для обработки триггера большого двоичного объекта, но только Error и выше для всего остального.

Версия 3.x

Версия 3.x пакета SDK использует фильтрацию, встроенную в .NET Core. Класс LogCategories позволяет определить категории для конкретных функций, триггеров или пользователей. Он также определяет фильтры для определенных состояний узла, таких как Startup и Results. Это позволяет точно настроить выходные данные журнала. Если в определенных категориях не найдено совпадение, фильтр возвращается к значению Default при принятии решения о фильтрации сообщения.

Добавьте в LogCategories следующий оператор:

using Microsoft.Azure.WebJobs.Logging; 

В следующем примере создается фильтр, который по умолчанию фильтрует все журналы на уровне Warning. Категории Function или results (эквивалентные Host.Results в версии 2.x) фильтруются на уровне Error. Фильтр сравнивает текущую категорию со всеми зарегистрированными уровнями в экземпляре LogCategories и выбирает самое длинное совпадение. Это означает, что уровень Debug, зарегистрированный для Host.Triggers, будет соответствовать Host.Triggers.Queue или Host.Triggers.Blob. Это позволит вам управлять более широкими категориями, не добавляя их.

static async Task Main(string[] args)
{
    var builder = new HostBuilder();
    builder.ConfigureWebJobs(b =>
    {
        b.AddAzureStorageCoreServices();
    });
    builder.ConfigureLogging(logging =>
            {
                logging.SetMinimumLevel(LogLevel.Warning);
                logging.AddFilter("Function", LogLevel.Error);
                logging.AddFilter(LogCategories.CreateFunctionCategory("MySpecificFunctionName"),
                    LogLevel.Debug);
                logging.AddFilter(LogCategories.Results, LogLevel.Error);
                logging.AddFilter("Host.Triggers", LogLevel.Debug);
            });
    var host = builder.Build();
    using (host)
    {
        await host.RunAsync();
    }
}

Версия 2.x

В версии 2.x пакета SDK класс LogCategoryFilter используется для управления фильтрацией. Фильтр LogCategoryFilter имеет свойство Default с начальным значением Information, что означает, что все сообщения с уровнями Information, Warning, Error или Critical регистрируются в журнале, а любые сообщения с уровнями Debug или Trace отфильтровываются.

Как и LogCategories в версии 3.x, свойство CategoryLevels позволяет указать уровни журналов для определенных категорий, чтобы вы могли точно настроить выходные данные журнала. Если в словаре CategoryLevels не найдено совпадение, фильтр возвращается к значению Default при принятии решения о фильтрации сообщения.

В следующем примере создается фильтр, который по умолчанию фильтрует все журналы на уровне Warning. Категории Function или Host.Results фильтруются на уровне Error. Фильтр LogCategoryFilter сравнивает текущую категорию со всеми зарегистрированными уровнями CategoryLevels и выбирает самое длинное совпадение. Это означает, что уровень Debug, зарегистрированный для Host.Triggers, будет соответствовать Host.Triggers.Queue или Host.Triggers.Blob. Это позволит вам управлять более широкими категориями, не добавляя их.

var filter = new LogCategoryFilter();
filter.DefaultLevel = LogLevel.Warning;
filter.CategoryLevels[LogCategories.Function] = LogLevel.Error;
filter.CategoryLevels[LogCategories.Results] = LogLevel.Error;
filter.CategoryLevels["Host.Triggers"] = LogLevel.Debug;

config.LoggerFactory = new LoggerFactory()
    .AddApplicationInsights(instrumentationKey, filter.Filter)
    .AddConsole(filter.Filter);

Пользовательские данные телеметрии для Application Insights

Процесс реализации пользовательской телеметрии для Application Insights зависит от версии пакета SDK. Чтобы узнать, как настроить Application Insights, ознакомьтесь с разделом Добавление журнала Application Insights.

Версия 3.x

Так как версия 3.x пакета SDK для веб-заданий использует универсальный узел .NET Core, настраиваемая фабрика данных телеметрии больше не предоставляется. Однако вы можете добавить пользовательскую телеметрию в конвейер, используя внедрение зависимостей. Для примеров в этом разделе необходимы следующие операторы using:

using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.ApplicationInsights.Channel;

Следующая пользовательская реализация ITelemetryInitializer позволяет добавлять собственную ITelemetry в TelemetryConfiguration по умолчанию.

internal class CustomTelemetryInitializer : ITelemetryInitializer
{
    public void Initialize(ITelemetry telemetry)
    {
        // Do something with telemetry.
    }
}

Вызовите ConfigureServices в конструкторе, чтобы добавить пользовательский ITelemetryInitializer в конвейер.

static async Task Main()
{
    var builder = new HostBuilder();
    builder.ConfigureWebJobs(b =>
    {
        b.AddAzureStorageCoreServices();
    });
    builder.ConfigureLogging((context, b) =>
    {
        // Add logging providers.
        b.AddConsole();

        // If this key exists in any config, use it to enable Application Insights.
        string appInsightsKey = context.Configuration["APPINSIGHTS_INSTRUMENTATIONKEY"];
        if (!string.IsNullOrEmpty(appInsightsKey))
        {
            // This uses the options callback to explicitly set the instrumentation key.
            b.AddApplicationInsights(o => o.InstrumentationKey = appInsightsKey);
        }
    });
    builder.ConfigureServices(services =>
        {
            services.AddSingleton<ITelemetryInitializer, CustomTelemetryInitializer>();
        });
    var host = builder.Build();
    using (host)
    {
        await host.RunAsync();
    }
}

Когда TelemetryConfiguration создана, все зарегистрированные типы ITelemetryInitializer включены. Дополнительные сведения см. в разделе API Application Insights для настраиваемых событий и метрик.

В версии 3.x больше не нужно освобождать TelemetryClient при остановке узла. Система внедрения зависимостей .NET Core автоматически удаляет зарегистрированный ApplicationInsightsLoggerProvider, который очищает TelemetryClient.

Версия 2.x

В версии 2.xTelemetryClient, созданный изнутри поставщиком Application Insights для пакета SDK для веб-заданий, использует ServerTelemetryChannel. Когда конечная точка Application Insights недоступна или регулирует входящие запросы, этот канал сохраняет запросы в файловой системе веб-приложения и позже повторно отправляет их.

Клиент TelemetryClient создается классом, который реализует ITelemetryClientFactory. По умолчанию это DefaultTelemetryClientFactory.

Если вы хотите изменить любую часть конвейера Application Insights, вы можете указать свою фабрику ITelemetryClientFactory, и узел будет использовать ваш класс для создания клиента TelemetryClient. Например, этот код переопределяет DefaultTelemetryClientFactory, чтобы изменить свойство ServerTelemetryChannel.

private class CustomTelemetryClientFactory : DefaultTelemetryClientFactory
{
    public CustomTelemetryClientFactory(string instrumentationKey, Func<string, LogLevel, bool> filter)
        : base(instrumentationKey, new SamplingPercentageEstimatorSettings(), filter)
    {
    }

    protected override ITelemetryChannel CreateTelemetryChannel()
    {
        ServerTelemetryChannel channel = new ServerTelemetryChannel();

        // Change the default from 30 seconds to 15 seconds.
        channel.MaxTelemetryBufferDelay = TimeSpan.FromSeconds(15);

        return channel;
    }
}

Объект SamplingPercentageEstimatorSettings настраивает адаптивную выборку. Это означает, что в некоторых сценариях с большим количеством операций Applications Insights отправляет выбранное подмножество данных телеметрии на сервер.

После создания фабрики данных телеметрии ее нужно передать поставщику ведения журнала Application Insights.

var clientFactory = new CustomTelemetryClientFactory(instrumentationKey, filter.Filter);

config.LoggerFactory = new LoggerFactory()
    .AddApplicationInsights(clientFactory);

Дальнейшие действия

В этой статье приведены фрагменты кода, демонстрирующие, как обрабатывать общие сценарии для работы с пакетом SDK для веб-заданий. Полные примеры см. на странице с примерами azure-webjobs-sdk-samples.