Partilhar via


How to use the Azure WebJobs SDK for event-driven background processing (Como utilizar o SDK de WebJobs do Azure para processamento em segundo plano condicionado por eventos)

Este artigo fornece orientação sobre como trabalhar com o SDK do Azure WebJobs. Para começar a usar WebJobs imediatamente, consulte Introdução ao SDK do Azure WebJobs.

Versões do SDK de WebJobs

Estas são as principais diferenças entre a versão 3.x e versão 2.x do SDK WebJobs:

  • Versão 3.x adiciona suporte para .NET Core.
  • Na versão 3.x, você instalará a extensão de vinculação de armazenamento exigida pelo SDK WebJobs. Na versão 2.x, as associações de armazenamento estão incluídas no SDK.
  • Ferramentas do Visual Studio 2019 para .NET Core (3.x) os projetos diferem das ferramentas para o .NET Framework (2.x) projetos. Para saber mais, consulte Desenvolver e implantar WebJobs usando o Visual Studio - Serviço de Aplicativo do Azure.

Várias descrições neste artigo fornecem exemplos para ambos WebJobs versão 3.x e WebJobs versão 2.x.

O Azure Functions é baseado no SDK de WebJobs.

  • Azure Functions versão 2.x é construído em WebJobs SDK versão 3.x.
  • Azure Functions versão 1.x é construído em WebJobs SDK versão 2.x.

Os repositórios de código-fonte para o SDK do Azure Functions e WebJobs usam a numeração do SDK do WebJobs. Várias seções deste artigo de instruções têm link para a documentação do Azure Functions.

Para obter mais informações, consulte Comparar o SDK de WebJobs e o Azure Functions

Anfitrião WebJobs

O host é um contêiner de tempo de execução para funções. O Host escuta as funções de gatilhos e chamadas. Na versão 3.x, o host é uma implementação do IHost. Na versão 2.x, você usa o JobHost objeto. Você cria uma instância de host em seu código e escreve código para personalizar seu comportamento.

Essa é uma diferença fundamental entre usar o SDK de WebJobs diretamente e usá-lo indiretamente por meio do Azure Functions. No Azure Functions, o serviço controla o host e você não pode personalizá-lo escrevendo código. O Azure Functions permite personalizar o comportamento do host por meio de configurações no arquivo host.json. Essas configurações são strings, não código, e o uso dessas strings limita os tipos de personalizações que você pode fazer.

Conexões de host

O SDK WebJobs procura conexões do Armazenamento do Azure e do Barramento de Serviço do Azure no arquivo local.settings.json quando você executa localmente ou no ambiente do WebJob quando executa no Azure. Por padrão, o SDK WebJobs requer uma conexão de armazenamento com o nome AzureWebJobsStorage.

Quando o nome da conexão é resolvido para um único valor exato, o tempo de execução identifica o valor como uma cadeia de conexão, que normalmente inclui um segredo. Os detalhes de uma cadeia de conexão dependem do serviço ao qual você se conecta. No entanto, um nome de conexão também pode se referir a uma coleção de vários itens de configuração, úteis para configurar conexões baseadas em identidade. As variáveis de ambiente podem ser tratadas como uma coleção usando um prefixo compartilhado que termina em sublinhados __duplos. O grupo pode então ser referenciado definindo o nome da conexão para esse prefixo.

Por exemplo, a propriedade para uma definição de gatilho connection de Blob do Azure pode ser Storage1. Contanto que não haja um único valor de cadeia de caracteres configurado por uma variável de ambiente chamada Storage1, uma variável de ambiente nomeada Storage1__blobServiceUri pode ser usada para informar a blobServiceUri propriedade da conexão. As propriedades de conexão são diferentes para cada serviço. Consulte a documentação do componente que usa a conexão.

Conexões baseadas em identidade

Para usar conexões baseadas em identidade no SDK WebJobs, certifique-se de estar usando as versões mais recentes dos pacotes WebJobs em seu projeto. Você também deve garantir que tenha uma referência a Microsoft.Azure.WebJobs.Host.Storage. A seguir está um exemplo de como seu arquivo de projeto pode parecer depois de fazer essas atualizações:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net48</TargetFramework>
    <IsWebJobProject>true</IsWebJobProject>
    <WebJobName>$(AssemblyName)</WebJobName>
    <WebJobType>Continuous</WebJobType>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Azure.WebJobs" Version="3.0.41" />
    <PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Storage.Queues" Version="5.3.1" />
    <PackageReference Include="Microsoft.Azure.WebJobs.Host.Storage" Version="5.0.1" />
    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.1.1" />
  </ItemGroup>

  <ItemGroup>
    <None Update="appsettings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
  </ItemGroup>
</Project>

Ao configurar WebJobs em seu HostBuilder, certifique-se de incluir uma chamada para AddAzureStorageCoreServices, pois é isso que permite AzureWebJobsStorage que outros gatilhos e associações de armazenamento usem identidade:

    builder.ConfigureWebJobs(b =>
    {
        b.AddAzureStorageCoreServices();
        // other configurations...
    });

Em seguida, você pode configurar a conexão definindo variáveis de AzureWebJobsStorage ambiente (ou Configurações do Aplicativo quando hospedado no Serviço de Aplicativo):

Variável de ambiente Description Valor de exemplo
AzureWebJobsStorage__blobServiceUri O URI do plano de dados do serviço de blob da conta de armazenamento, usando o esquema HTTPS. https://< storage_account_name.blob.core.windows.net>
AzureWebJobsStorage__queueServiceUri O URI do plano de dados do serviço de fila da conta de armazenamento, usando o esquema HTTPS. https://< storage_account_name.queue.core.windows.net>

Se você fornecer sua configuração por qualquer meio que não seja variáveis de ambiente, como com um appsettings.json, em vez disso, você precisará fornecer configuração estruturada para a conexão e suas propriedades:

{
    "AzureWebJobsStorage": {
        "blobServiceUri": "https://<storage_account_name>.blob.core.windows.net",
        "queueServiceUri": "https://<storage_account_name>.queue.core.windows.net"
    }
}

Você pode omitir a queueServiceUri propriedade se não planeja usar gatilhos de blob.

Quando seu código é executado localmente, o padrão é usar sua identidade de desenvolvedor de acordo com o comportamento descrito para DefaultAzureCredential.

Quando seu código é hospedado no Serviço de Aplicativo do Azure, a configuração mostrada acima será padrão para a identidade gerenciada atribuída pelo sistema para o recurso. Para usar uma identidade atribuída ao usuário que foi atribuída ao aplicativo, você precisa adicionar propriedades adicionais para sua conexão que especifiquem qual identidade deve ser usada. A credential propriedade (AzureWebJobsStorage__credential como uma variável de ambiente) deve ser definida como a string "managedidentity". A clientId propriedade (AzureWebJobsStorage__clientId como uma variável de ambiente) deve ser definida como a ID do cliente da identidade gerenciada atribuída pelo usuário a ser usada. Como configuração estruturada, o objeto completo seria:

{
    "AzureWebJobsStorage": {
        "blobServiceUri": "https://<storage_account_name>.blob.core.windows.net",
        "queueServiceUri": "https://<storage_account_name>.queue.core.windows.net",
        "credential": "managedidentity",
        "clientId": "<user-assigned-identity-client-id>"
    }
}

A identidade usada para AzureWebJobsStorage deve ter atribuições de função que lhe concedam as funções de Proprietário de Dados de Blob de Armazenamento, Colaborador de Dados da Fila de Armazenamento e Colaborador de Conta de Armazenamento . Você pode omitir o Colaborador de Dados da Fila de Armazenamento e o Colaborador da Conta de Armazenamento se não planeja usar gatilhos de blob.

A tabela a seguir mostra funções internas que são recomendadas ao usar gatilhos em associações em operação normal. Seu aplicativo pode exigir permissões adicionais com base no código que você escreve.

Enlace Exemplo de funções internas
Blob trigger Proprietário de dados de Blob de armazenamento e contribuidor de dados da fila de armazenamento
Veja acima os requisitos também AzureWebJobsStorage .
Blob (entrada) Leitor de Dados do Armazenamento de Blobs
Blob (saída) Proprietário dos Dados do Armazenamento de Blobs
Queue trigger Leitor de dados da fila de armazenamento, processador de mensagens de dados da fila de armazenamento
Fila (saída) Contribuidor de dados da fila de armazenamento, remetente de mensagem de dados da fila de armazenamento
Gatilho doService Bus 1 Recetor de Dados do Barramento de Serviço do Azure, Proprietário de Dados do Barramento de Serviço do Azure
Service Bus (saída) Remetente de dados do Barramento de Serviço do Azure

1 Para acionar a partir de tópicos do Service Bus, a atribuição de função precisa ter escopo efetivo sobre o recurso de assinatura do Service Bus. Se apenas estiver incluído o tópico, ocorrerá um erro. Alguns clientes, como o portal do Azure, não expõem o recurso de subscrição do Service Bus como um âmbito para atribuição de função. Nesses casos, a CLI do Azure pode ser usada. Para saber mais, consulte Funções internas do Azure para o Barramento de Serviço do Azure.

Cadeias de conexão na versão 2.x

Versão 2.x do SDK não requer um nome específico. Versão 2.x permite que você use seus próprios nomes para essas cadeias de conexão e permite armazená-los em outro lugar. Você pode definir nomes no código usando o JobHostConfiguration, como este:

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

Nota

Porque a versão 3.x usa as APIs de configuração padrão do .NET Core, não há nenhuma API para alterar nomes de cadeia de conexão. Consulte Desenvolver e implantar WebJobs usando o Visual Studio

Configurações de desenvolvimento do host

Você pode executar o host no modo de desenvolvimento para tornar o desenvolvimento local mais eficiente. Aqui estão algumas das configurações que mudam automaticamente quando você executa no modo de desenvolvimento:

Property Configuração de desenvolvimento
Tracing.ConsoleLevel TraceLevel.Verbose para maximizar a saída do log.
Queues.MaxPollingInterval Um valor baixo para garantir que os métodos de fila sejam acionados imediatamente.
Singleton.ListenerLockPeriod 15 segundos para ajudar no rápido desenvolvimento iterativo.

O processo para habilitar o modo de desenvolvimento depende da versão do SDK.

Versão 3.x

Versão 3.x usa o padrão ASP.NET Core APIs. Chame HostBuilder o UseEnvironment método na instância. Passe uma cadeia de caracteres chamada development, como neste exemplo:

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

Versão 2.x

A JobHostConfiguration classe tem um método que permite o UseDevelopmentSettings modo de desenvolvimento. O exemplo a seguir mostra como usar as configurações de desenvolvimento. Para retornar config.IsDevelopment true quando ele for executado localmente, defina uma variável de ambiente local nomeada AzureWebJobsEnv com o valor Development.

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

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

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

Gerenciando conexões simultâneas (versão 2.x)

Na versão 3.x, o limite de conexão padrão para conexões infinitas. Se, por algum motivo, você precisar alterar esse limite, poderá usar a MaxConnectionsPerServer WinHttpHandler propriedade da classe.

Na versão 2.x, você controla o número de conexões simultâneas com um host usando a API ServicePointManager.DefaultConnectionLimit . Em 2.x, você deve aumentar esse valor a partir do padrão de 2 antes de iniciar seu host WebJobs.

Todas as solicitações HTTP de saída feitas a partir de uma função usando HttpClient o fluxo através ServicePointManagerdo . Depois de atingir o valor definido em DefaultConnectionLimit, ServicePointManager começa a enfileirar solicitações antes de enviá-las. Suponha que seu DefaultConnectionLimit está definido como 2 e seu código faz 1.000 solicitações HTTP. Inicialmente, apenas duas solicitações são permitidas através do sistema operacional. Os outros 998 estão na fila até que haja espaço para eles. Isso significa que você HttpClient pode atingir o tempo limite porque parece ter feito a solicitação, mas a solicitação nunca foi enviada pelo sistema operacional para o servidor de destino. Assim, você pode ver um comportamento que não parece fazer sentido: seu local HttpClient está levando 10 segundos para concluir uma solicitação, mas seu serviço está retornando todas as solicitações em 200 ms.

O valor padrão para aplicativos ASP.NET é Int32.MaxValue, e é provável que funcione bem para WebJobs em execução em um Plano de Serviço de Aplicativo Básico ou superior. Os WebJobs normalmente precisam da configuração Always On , e isso é suportado apenas pelos Planos de Serviço de Aplicativo Básicos e superiores.

Se o WebJob estiver sendo executado em um Plano de Serviço de Aplicativo Gratuito ou Compartilhado, seu aplicativo será restrito pela área restrita do Serviço de Aplicativo, que atualmente tem um limite de conexão de 300. Com um limite de conexão não acoplada no ServicePointManager, é mais provável que o limite de conexão de área restrita seja atingido e o site seja encerrado. Nesse caso, definir DefaultConnectionLimit para algo mais baixo, como 50 ou 100, pode impedir que isso aconteça e ainda permitir uma taxa de transferência suficiente.

A configuração deve ser configurada antes que qualquer solicitação HTTP seja feita. Por esse motivo, o host WebJobs não deve ajustar a configuração automaticamente. Pode haver solicitações HTTP que ocorrem antes do host iniciar, o que pode levar a um comportamento inesperado. A melhor abordagem é definir o valor imediatamente em seu Main método antes de inicializar JobHost, como mostrado aqui:

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

Acionadores

O SDK de WebJobs dá suporte ao mesmo conjunto de gatilhos e associações usados pelo Azure Functions. Observe que no SDK do WebJobs, os gatilhos são específicos da função e não estão relacionados ao tipo de implantação do WebJob. WebJobs com funções acionadas por eventos criadas usando o SDK devem sempre ser publicados como um WebJob contínuo , com Always on habilitado.

As funções devem ser métodos públicos e devem ter um atributo trigger ou o NoAutomaticTrigger atributo.

Gatilhos automáticos

Os gatilhos automáticos chamam uma função em resposta a um evento. Considere este exemplo de uma função acionada por uma mensagem adicionada ao armazenamento de filas do Azure. A função responde lendo um blob do armazenamento de Blob do 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");
}

O QueueTrigger atributo diz ao tempo de execução para chamar a função sempre que uma mensagem de fila aparecer no myqueue-items. O Blob atributo diz ao tempo de execução para usar a mensagem de fila para ler um blob no contêiner sample-workitems . O nome do item de blob no samples-workitems contêiner é obtido diretamente do gatilho de fila como uma expressão de ligação ({queueTrigger}).

Nota

Um aplicativo Web pode atingir o tempo limite após 20 minutos de inatividade, e somente solicitações para o aplicativo Web real podem redefinir o temporizador. Exibir a configuração do aplicativo no portal do Azure ou fazer solicitações para o site de ferramentas avançadas (https://<app_name>.scm.azurewebsites.net) não redefine o temporizador. Se você definir o aplicativo Web que hospeda seu trabalho para ser executado continuamente, executado em uma agenda ou usar gatilhos controlados por eventos, habilite a configuração Sempre ligado na página Configuração do Azure do seu aplicativo Web. A configuração Sempre ligado ajuda a garantir que esses tipos de WebJobs sejam executados de forma confiável. Esse recurso está disponível apenas nos níveis de preços Basic, Standard e Premium.

Gatilhos manuais

Para acionar uma função manualmente, use o atributo NoAutomaticTrigger , como mostrado aqui:

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

O processo para acionar manualmente a função depende da versão do SDK.

Versão 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();
    }
}

Versão 2.x

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

Ligações de entrada e saída

As associações de entrada fornecem uma maneira declarativa de disponibilizar dados do Azure ou de serviços de terceiros para seu código. As ligações de saída fornecem uma maneira de atualizar dados. O artigo Introdução mostra um exemplo de cada um.

Você pode usar um valor de retorno de método para uma associação de saída aplicando o atributo ao valor de retorno do método. Veja o exemplo em Usando o valor de retorno da Função do Azure.

Tipos de vinculação

O processo de instalação e gerenciamento de tipos de vinculação depende se você está usando a versão 3.x ou versão 2.x do SDK. Você pode encontrar o pacote a ser instalado para um tipo de associação específico na seção "Pacotes" do artigo de referência do Azure Functions desse tipo de associação. Uma exceção é o gatilho e a associação de arquivos Arquivos (para o sistema de arquivos local), que não é suportado pelo Azure Functions.

Versão 3.x

Na versão 3.x, as ligações de armazenamento estão incluídas no Microsoft.Azure.WebJobs.Extensions.Storage pacote. Chame ConfigureWebJobs o AddAzureStorage método de extensão no método, como mostrado aqui:

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

Para usar outros tipos de gatilho e ligação, instale o pacote NuGet que os contém e chame o Add<binding> método de extensão implementado na extensão. Por exemplo, se você quiser usar uma associação do Azure Cosmos DB, instale Microsoft.Azure.WebJobs.Extensions.CosmosDB e chame AddCosmosDB, desta forma:

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

Para usar o gatilho de Timer ou a associação de arquivos, que fazem parte dos serviços principais, chame os AddTimers métodos de extensão ou AddFiles .

Versão 2.x

Esses tipos de gatilho e vinculação estão incluídos na versão 2.x do Microsoft.Azure.WebJobs pacote:

  • Armazenamento de Blobs
  • Armazenamento de filas
  • Armazenamento de tabelas

Para usar outros tipos de gatilho e ligação, instale o pacote NuGet que os contém e chame JobHostConfiguration um Use<binding> método no objeto. Por exemplo, se você quiser usar um gatilho de Timer, instale Microsoft.Azure.WebJobs.Extensions e chame UseTimers o Main método, conforme mostrado aqui:

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

Para usar a ligação Arquivos, instale Microsoft.Azure.WebJobs.Extensions e chame UseFileso .

ExecutionContext

WebJobs permite que você se associe a um ExecutionContextarquivo . Com essa ligação, você pode acessar o ExecutionContext como um parâmetro em sua assinatura de função. Por exemplo, o código a seguir usa o objeto de contexto para acessar a ID de invocação, que você pode usar para correlacionar todos os logs produzidos por uma determinada chamada de função.

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

O processo de vinculação ao depende da sua versão do ExecutionContext SDK.

Versão 3.x

Chame ConfigureWebJobs o AddExecutionContextBinding método de extensão no método, como mostrado aqui:

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

Versão 2.x

O Microsoft.Azure.WebJobs.Extensions pacote mencionado anteriormente também fornece um tipo de vinculação especial que você pode registrar chamando o UseCore método. Essa associação permite definir um parâmetro na assinatura da ExecutionContext função, que é habilitada da seguinte forma:

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

Configuração de vinculação

Você pode configurar o comportamento de alguns gatilhos e associações. O processo para configurá-los depende da versão do SDK.

  • Versão 3.x: Defina a configuração quando o Add<Binding> método for chamado em ConfigureWebJobs.
  • Versão 2.x: Defina a configuração definindo propriedades em um objeto de configuração para o qual você passa para JobHost.

Essas configurações específicas de associação são equivalentes às configurações no arquivo de projeto host.json no Azure Functions.

Você pode configurar as seguintes associações:

Configuração de gatilho do Azure Cosmos DB (versão 3.x)

Este exemplo mostra como configurar o gatilho do 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();
    }
}

Para obter mais informações, consulte o artigo de vinculação do Azure Cosmos DB.

Os Hubs de Eventos acionam a configuração (versão 3.x)

Este exemplo mostra como configurar o gatilho Hubs de Eventos:

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

Para obter mais informações, consulte o artigo de vinculação de Hubs de Eventos.

Configuração do gatilho de armazenamento em fila

Os exemplos a seguir mostram como configurar o gatilho de armazenamento de fila.

Versão 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();
    }
}

Para obter mais informações, consulte o artigo Vinculação de armazenamento em fila.

Versão 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();
}

Para obter mais informações, consulte a referência host.json v1.x.

Configuração de vinculação do SendGrid (versão 3.x)

Este exemplo mostra como configurar a ligação de saída 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();
    }
}

Para obter mais informações, consulte o artigo de vinculação SendGrid.

Configuração de gatilho do Service Bus (versão 3.x)

Este exemplo mostra como configurar o gatilho do Service Bus:

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

Para obter mais detalhes, consulte o artigo de vinculação do Service Bus.

Configuração para outras ligações

Alguns tipos de gatilho e associação definem seus próprios tipos de configuração personalizada. Por exemplo, o gatilho File permite especificar o caminho raiz a ser monitorado, como nos exemplos a seguir.

Versão 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();
    }
}

Versão 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();
}

Expressões de enlace

Em parâmetros do construtor de atributos, você pode usar expressões que resolvem para valores de várias fontes. Por exemplo, no código a seguir, o caminho para o BlobTrigger atributo cria uma expressão chamada filename. Quando usado para a ligação de saída, filename resolve para o nome do blob de acionamento.

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

Para obter mais informações sobre expressões de associação, consulte Vinculando expressões e padrões na documentação do Azure Functions.

Expressões de vinculação personalizadas

Às vezes, você deseja especificar um nome de fila, um nome de blob ou contêiner ou um nome de tabela no código em vez de codificá-lo. Por exemplo, talvez você queira especificar o nome da fila para o QueueTrigger atributo em um arquivo de configuração ou variável de ambiente.

Você pode fazer isso passando um resolvedor de nome personalizado durante a configuração. Você inclui espaços reservados em parâmetros do construtor de atributos de gatilho ou vinculação, e seu código de resolvedor fornece os valores reais a serem usados no lugar desses espaços reservados. Você identifica espaços reservados cercando-os com sinais de porcentagem (%), conforme mostrado aqui:

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

Esse código permite que você use uma fila nomeada logqueuetest no ambiente de teste e uma chamada logqueueprod na produção. Em vez de um nome de fila codificado, especifique o nome de uma entrada na appSettings coleção.

Há um resolvedor padrão que entra em vigor se você não fornecer um personalizado. O padrão obtém valores de configurações de aplicativo ou variáveis de ambiente.

A partir do .NET Core 3.1, o ConfigurationManager uso requer o pacote NuGet System.Configuration.ConfigurationManager. O exemplo requer a seguinte using instrução:

using System.Configuration;

Sua NameResolver classe obtém o nome da fila nas configurações do aplicativo, conforme mostrado aqui:

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

Versão 3.x

Configure o resolvedor usando a injeção de dependência. Esses exemplos exigem a seguinte using instrução:

using Microsoft.Extensions.DependencyInjection;

Você adiciona o resolvedor chamando o ConfigureServices método de extensão no HostBuilder, como neste exemplo:

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

Versão 2.x

Passe sua NameResolver classe para o JobHost objeto, conforme mostrado aqui:

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

O Azure Functions implementa INameResolver para obter valores das configurações do aplicativo, conforme mostrado no exemplo. Ao usar o SDK WebJobs diretamente, você pode escrever uma implementação personalizada que obtém valores de substituição de espaço reservado de qualquer fonte de sua preferência.

Vinculação em tempo de execução

Se você precisar fazer algum trabalho em sua função antes de usar um atributo de vinculação como Queue, Blobou Table, você pode usar a IBinder interface.

O exemplo a seguir pega uma mensagem de fila de entrada e cria uma nova mensagem com o mesmo conteúdo em uma fila de saída. O nome da fila de saída é definido por código no corpo da função.

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

Para obter mais informações, consulte Vinculação em tempo de execução na documentação do Azure Functions.

Informações de referência vinculativas

A documentação do Azure Functions fornece informações de referência sobre cada tipo de associação. Você encontrará as seguintes informações em cada artigo de referência de vinculação. (Este exemplo é baseado na fila de armazenamento.)

  • Embalagens. O pacote que você precisa instalar para incluir suporte para a associação em um projeto SDK WebJobs.
  • Exemplos. Exemplos de código. O exemplo de biblioteca de classes C# se aplica ao SDK WebJobs. Basta omitir o FunctionName atributo.
  • Atributos. Os atributos a serem usados para o tipo de vinculação.
  • Configuração. Explicações das propriedades do atributo e parâmetros do construtor.
  • Utilização. Os tipos aos quais você pode vincular e informações sobre como a associação funciona. Por exemplo: algoritmo de sondagem, processamento de fila de veneno.

Nota

As ligações HTTP, Webhooks e Grade de Eventos são suportadas apenas pelo Azure Functions, não pelo SDK WebJobs.

Para obter uma lista completa das associações suportadas no tempo de execução do Azure Functions, consulte Associações suportadas.

Atributos para Desativar, Tempo Limite e Singleton

Com esses atributos, você pode controlar o acionamento de funções, cancelar funções e garantir que apenas uma instância de uma função seja executada.

Desativar atributo

O Disable atributo permite controlar se uma função pode ser acionada.

No exemplo a seguir, se a configuração Disable_TestJob do aplicativo tiver um valor de ou True (sem distinção entre maiúsculas e 1 minúsculas), a função não será executada. Nesse caso, o tempo de execução cria uma mensagem de log A função 'Functions.TestJob' está desativada.

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

Quando você altera os valores de configuração do aplicativo no portal do Azure, o WebJob é reiniciado para pegar a nova configuração.

O atributo pode ser declarado no nível do parâmetro, método ou classe. O nome da configuração também pode conter expressões de ligação.

Atributo Tempo limite

O Timeout atributo faz com que uma função seja cancelada se ela não for concluída dentro de um período de tempo especificado. No exemplo a seguir, a função seria executada por um dia sem o atributo Timeout. O tempo limite faz com que a função seja cancelada após 15 segundos. Quando o parâmetro "throwOnError" do atributo Timeout é definido como "true", a invocação da função é encerrada por ter uma exceção lançada pelo SDK de webjobs quando o intervalo de tempo limite é excedido. O valor padrão de "throwOnError" é "false". Quando o atributo Timeout é usado, o comportamento padrão é cancelar a invocação da função definindo o token de cancelamento enquanto permite que a invocação seja executada indefinidamente até que o código da função retorne ou lance uma exceção.

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

Você pode aplicar o atributo Timeout no nível de classe ou método e pode especificar um tempo limite global usando JobHostConfiguration.FunctionTimeout. Os tempos limite de nível de classe ou de método substituem os tempos limite globais.

Atributo Singleton

O Singleton atributo garante que apenas uma instância de uma função seja executada, mesmo quando há várias instâncias do aplicativo Web host. O atributo Singleton usa bloqueio distribuído para garantir que uma instância seja executada.

Neste exemplo, apenas uma única instância da função é executada ProcessImage a qualquer momento:

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

SingletonMode.Listener

Alguns gatilhos têm suporte interno para gerenciamento de simultaneidade:

  • QueueTrigger. Defina JobHostConfiguration.Queues.BatchSize como 1.
  • ServiceBusTrigger. Defina ServiceBusConfiguration.MessageOptions.MaxConcurrentCalls como 1.
  • FileTrigger. Defina FileProcessor.MaxDegreeOfParallelism como 1.

Você pode usar essas configurações para garantir que sua função seja executada como um singleton em uma única instância. Para garantir que apenas uma única instância da função esteja em execução quando o aplicativo Web for expandido para várias instâncias, aplique um bloqueio singleton no nível do ouvinte na função ([Singleton(Mode = SingletonMode.Listener)]). Os bloqueios de ouvinte são adquiridos quando o JobHost é iniciado. Se três instâncias dimensionadas forem iniciadas ao mesmo tempo, apenas uma das instâncias adquirirá o bloqueio e apenas um ouvinte será iniciado.

Nota

Consulte este repositório GitHub para saber mais sobre como o SingletonMode.Function funciona.

Valores de escopo

Você pode especificar uma expressão/valor de escopo em um singleton. A expressão/valor garante que todas as execuções da função em um escopo específico serão serializadas. Implementar um bloqueio mais granular dessa maneira pode permitir algum nível de paralelismo para sua função enquanto serializa outras invocações conforme ditado por seus requisitos. Por exemplo, no código a seguir, a expressão de escopo se liga ao Region valor da mensagem de entrada. Quando a fila contém três mensagens nas regiões Leste, Leste e Oeste, as mensagens com região Leste são executadas em série. A mensagem com a região Oeste é executada em paralelo com as da região Leste.

[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

O escopo padrão para um bloqueio é SingletonScope.Function, o que significa que o escopo de bloqueio (o caminho de concessão de blob) está vinculado ao nome da função totalmente qualificada. Para bloquear entre funções, especifique SingletonScope.Host e use um nome de ID de escopo que seja o mesmo em todas as funções que você não deseja executar simultaneamente. No exemplo a seguir, apenas uma instância de ou RemoveItem é executada AddItem de cada vez:

[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.
}

Visualizando blobs de leasing

O SDK de WebJobs usa concessões de blob do Azure sob as capas para implementar o bloqueio distribuído. Os blobs de leasing usados pela Singleton podem ser encontrados no azure-webjobs-host contêiner na AzureWebJobsStorage conta de armazenamento sob o caminho "locks". Por exemplo, o caminho do blob de concessão para o primeiro ProcessImage exemplo mostrado anteriormente pode ser locks/061851c758f04938a4426aa9ab3869c0/WebJobs.Functions.ProcessImage. Todos os caminhos incluem o ID JobHost, neste caso 061851c758f04938a4426aa9ab3869c0.

Funções assíncronas

Para obter informações sobre como codificar funções assíncronas, consulte a documentação do Azure Functions.

Tokens de cancelamento

Para obter informações sobre como lidar com tokens de cancelamento, consulte a documentação do Azure Functions sobre tokens de cancelamento e desligamento normal.

Múltiplas instâncias

Se seu aplicativo Web for executado em várias instâncias, um WebJob contínuo será executado em cada instância, ouvindo gatilhos e chamando funções. As várias associações de gatilho são projetadas para compartilhar eficientemente o trabalho de forma colaborativa entre instâncias, de modo que o dimensionamento para mais instâncias permita que você lide com mais carga.

Embora alguns gatilhos possam resultar em processamento duplo, os gatilhos de armazenamento de fila e blob impedem automaticamente que uma função processe uma mensagem de fila ou blob mais de uma vez. Para obter mais informações, consulte Projetando para entrada idêntica na documentação do Azure Functions.

O gatilho do temporizador garante automaticamente que apenas uma instância do temporizador seja executada, para que você não tenha mais de uma instância de função em execução em um determinado horário agendado.

Se quiser garantir que apenas uma instância de uma função seja executada mesmo quando houver várias instâncias do aplicativo Web host, você poderá usar o Singleton atributo.

Filtros

Os Filtros de Função (visualização) fornecem uma maneira de personalizar o pipeline de execução de WebJobs com sua própria lógica. Os filtros são semelhantes aos filtros ASP.NET Core. Você pode implementá-los como atributos declarativos que são aplicados às suas funções ou classes. Para obter mais informações, consulte Filtros de função.

Registos e monitorização

Recomendamos a estrutura de registro em log que foi desenvolvida para ASP.NET. O artigo Introdução mostra como usá-lo.

Filtragem de logs

Cada log criado por uma ILogger instância tem um associado Category e Level. LogLevel é uma enumeração e o código inteiro indica importância relativa:

Nível de Registo Código
Rastreio 0
Depurar 1
Informação 2
Aviso 3
Erro 4
Crítico 5
Nenhuma 6

Você pode filtrar de forma independente cada categoria para um arquivo LogLevel. Por exemplo, você pode querer ver todos os logs para processamento de gatilho de blob, mas apenas Error e superior para todo o resto.

Versão 3.x

Versão 3.x do SDK depende da filtragem incorporada no .NET Core. A LogCategories classe permite definir categorias para funções, gatilhos ou usuários específicos. Ele também define filtros para estados de host específicos, como Startup e Results. Isso permite que você ajuste a saída de log. Se nenhuma correspondência for encontrada dentro das categorias definidas, o filtro retornará ao Default valor ao decidir se deseja filtrar a mensagem.

LogCategories requer a seguinte instrução using:

using Microsoft.Azure.WebJobs.Logging; 

O exemplo a seguir constrói um filtro que, por padrão, filtra todos os Warning logs no nível. As Function e results categorias (equivalente à Host.Results versão 2.x) são filtrados ao Error nível. O filtro compara a categoria atual com todos os níveis registrados na LogCategories instância e escolhe a correspondência mais longa. Isto significa que o nível registado Debug para Host.Triggers as partidas Host.Triggers.Queue ou Host.Triggers.Blob. Isso permite que você controle categorias mais amplas sem precisar adicionar cada uma.

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

Versão 2.x

Na versão 2.x do SDK, você usa a classe para controlar a LogCategoryFilter filtragem. O LogCategoryFilter tem uma Default propriedade com um valor inicial de Information, o que significa que todas as Informationmensagens nos níveis , Warning, Errorou Critical são registradas, mas todas as mensagens nos Debug níveis ou Trace são filtradas.

Tal como na LogCategories versão 3.x, a CategoryLevels propriedade permite especificar níveis de log para categorias específicas para que você possa ajustar a saída de log. Se nenhuma correspondência for encontrada no CategoryLevels dicionário, o filtro retornará ao Default valor ao decidir se deseja filtrar a mensagem.

O exemplo a seguir constrói um filtro que, por padrão, filtra todos os logs no Warning nível. As Function categorias e Host.Results são filtradas no Error nível. O LogCategoryFilter compara a categoria atual com todos os inscritos CategoryLevels e escolhe a partida mais longa. Assim, o nível registado Debug para Host.Triggers irá corresponder ou Host.Triggers.Queue Host.Triggers.Blob. Isso permite que você controle categorias mais amplas sem precisar adicionar cada uma.

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

Telemetria personalizada para o Application Insights

O processo de implementação da telemetria personalizada para o Application Insights depende da versão do SDK. Para saber como configurar o Application Insights, consulte Adicionar log do Application Insights.

Versão 3.x

Porque a versão 3.x do SDK WebJobs depende do host genérico .NET Core, uma fábrica de telemetria personalizada não é mais fornecida. Mas você pode adicionar telemetria personalizada ao pipeline usando a injeção de dependência. Os exemplos nesta seção exigem as seguintes using instruções:

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

A seguinte implementação personalizada do ITelemetryInitializer permite que você adicione o seu próprio ITelemetry ao padrão TelemetryConfiguration.

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

Chame ConfigureServices o construtor para adicionar seu personalizado ITelemetryInitializer ao pipeline.

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

Quando o TelemetryConfiguration é construído, todos os tipos registrados de ITelemetryInitializer são incluídos. Para saber mais, consulte API do Application Insights para eventos e métricas personalizados.

Na versão 3.x, você não precisa mais liberar o TelemetryClient quando o host para. O sistema de injeção de dependência do .NET Core descarta automaticamente o registro ApplicationInsightsLoggerProvider, que libera o TelemetryClient.

Versão 2.x

Na versão 2.x, o TelemetryClient criado internamente pelo provedor do Application Insights para o SDK WebJobs usa ServerTelemetryChannel. Quando o ponto de extremidade do Application Insights não está disponível ou limitando as solicitações de entrada, esse canal salva as solicitações no sistema de arquivos do aplicativo Web e as reenvia posteriormente.

O TelemetryClient é criado por uma classe que implementa ITelemetryClientFactory. Por padrão, este é o DefaultTelemetryClientFactoryarquivo .

Se quiser modificar qualquer parte do pipeline do Application Insights, você pode fornecer o seu próprio ITelemetryClientFactory, e o host usará sua classe para construir um TelemetryClientarquivo . Por exemplo, esse código substitui DefaultTelemetryClientFactory para modificar uma propriedade de 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;
    }
}

O SamplingPercentageEstimatorSettings objeto configura a amostragem adaptável. Isso significa que, em determinados cenários de alto volume, o Applications Insights envia um subconjunto selecionado de dados de telemetria para o servidor.

Depois de criar a fábrica de telemetria, você a passa para o provedor de log do Application Insights:

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

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

Próximos passos

Este artigo forneceu trechos de código que mostram como lidar com cenários comuns para trabalhar com o SDK WebJobs. Para obter exemplos completos, consulte azure-webjobs-sdk-samples.