Partilhar via


Usar o SDK de WebJobs do Azure para processamento em segundo plano controlado por eventos

Este artigo descreve como trabalhar com o SDK do Azure WebJobs. Para começar rapidamente a usar WebJobs, consulte Introdução ao SDK do Azure WebJobs.

Versões do SDK de WebJobs

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

  • Versão 3.x adiciona suporte para .NET Core.
  • Na versão 3. x, você instala 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 os projetos .NET Core (3.x) diferem das ferramentas para os projetos .NET Framework (2.x). Para obter mais informações, consulte Desenvolver e implantar WebJobs usando o Visual Studio.

Alguns exemplos neste artigo são fornecidos para ambos WebJobs versão 3. x e WebJobs versão 2. x.

O Azure Functions baseia-se 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 é baseado em WebJobs SDK versão 2.x.

Os repositórios de código-fonte para o Azure Functions e o SDK WebJobs usam a numeração do SDK WebJobs. Várias seções deste artigo estão vinculadas à 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 WebJobs é 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 alteração de arquitetura é 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. Não é possível personalizar o host escrevendo código. Nas Azure Functions, você personaliza o comportamento do host por meio de definiçõ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 do WebJobs procura conexões do Armazenamento do Azure e do Barramento de Serviço do Azure no ficheiro local.settings.json quando se executa localmente ou no ambiente do WebJob quando executado no Azure. Por padrão, o SDK WebJobs requer uma conexão de armazenamento chamada AzureWebJobsStorage.

Quando o nome da conexão se resolve a um único valor exato, o runtime identifica o valor como uma string 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. Esse método é útil para configurar conexões baseadas em identidade. Você pode tratar variáveis de ambiente como uma coleção usando um prefixo compartilhado que termina em sublinhados duplos (__). Em seguida, você pode fazer referência ao grupo definindo o nome da conexão para esse prefixo.

Por exemplo, a propriedade para a definição de um gatilho de Armazenamento de Blobs do Azure connection 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 usar as versões mais recentes dos pacotes WebJobs em seu projeto. Certifique-se também de que tem uma referência a Microsoft.Azure.WebJobs.Host.Storage.

O exemplo a seguir mostra a aparência do arquivo de projeto 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.42" />
    <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 sua instância do HostBuilder, certifique-se de incluir uma chamada para AddAzureStorageCoreServices. Essa chamada permite que AzureWebJobsStorage e outros gatilhos e ligações de armazenamento usem a identidade.

Aqui está um exemplo:

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

Em seguida, você pode configurar a conexão definindo variáveis de AzureWebJobsStorage ambiente (ou configurações de aplicativo quando seu código é hospedado no Serviço de Aplicativo do Azure):

Variável de ambiente Descrição Valor de exemplo
AzureWebJobsStorage__blobServiceUri O URI do plano de dados do serviço de blob da conta de armazenamento. Ele usa 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. Ele usa 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 em um appsettings.json arquivo de configuração, deverá fornecer uma 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 propriedade queueServiceUri se não planeia usar gatilhos de blobs.

Quando o código é executado localmente, o padrão é usar a identidade do desenvolvedor conforme descrito para DefaultAzureCredential.

Quando seu código é hospedado no Serviço de Aplicativo, a configuração no exemplo anterior assume como padrão a identidade gerenciada atribuída pelo sistema para o recurso. Para usar uma identidade atribuída ao usuário atribuída ao aplicativo, você deve adicionar propriedades para sua conexão para especificar qual identidade usar. A credential propriedade (AzureWebJobsStorage__credential como uma variável de ambiente) deve ser definida como a cadeia de caracteres 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 uma configuração estruturada, o objeto completo seria semelhante a este exemplo:

{
    "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 as funções Colaborador de Dados da Fila de Armazenamento e Colaborador da Conta de Armazenamento se não planeja usar gatilhos de blob.

A tabela a seguir mostra funções incorporadas que recomendamos quando se usam gatilhos em associações em operação normal. Seu aplicativo pode exigir mais permissões, dependendo do código que você escreve.

Encadernação Exemplo de funções internas
gatilho de blob Proprietário dos Dados de Armazenamento Blob eContribuidor dos Dados de Fila de Armazenamento
Consulte também os requisitos anteriores para AzureWebJobsStorage.
Blob (entrada) Leitor de Dados do Armazenamento de Blobs
Blob (saída) Proprietário de Dados do Armazenamento Blob
Disparador de fila Leitor de dados da fila de armazenamento, processador de mensagens de dados da fila de armazenamento
Fila (saída) Contribuinte de dados da fila de armazenamento, Remetedor de mensagem de dados da fila de armazenamento
Gatilho do Service Bus1 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 Azure Service Bus

1 Para acionar a partir de tópicos do Service Bus, a atribuição de função deve ter escopo efetivo sobre o recurso de assinatura do Service Bus. Se apenas o tópico for incluído, 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 cenários, você pode usar a CLI do Azure. Para obter mais informações, 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 para cadeias de conexão. Na versão 2. x, você pode usar seus próprios nomes para essas cadeias de conexão e armazená-las em outro lugar. Você pode definir nomes no código usando JobHostConfiguration, como neste exemplo:

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, nenhuma API existe para alterar nomes de cadeia de conexão. Para obter mais informações, 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:

Propriedade 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 com o rápido desenvolvimento iterativo.

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

Versão 3.x

Na versão 3. x, você usa as APIs padrão do ASP.NET Core para alterar o ambiente do host. Chame o método UseEnvironment na instância HostBuilder. 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.IsDevelopmenttrue quando ele for executado localmente, defina uma variável de ambiente local chamada AzureWebJobsEnv que tenha o valor Development.

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

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

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

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

Na versão 3.x, o limite de conexão padrão é definido para conexões infinitas. Se, por algum motivo, tu precisares alterar este limite, podes usar a propriedade MaxConnectionsPerServer da classe WinHttpHandler.

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

Todas as solicitações HTTP de saída que faz a partir de uma função utilizando HttpClient passam através do ServicePointManager. Depois de atingir o valor definido em DefaultConnectionLimit, ServicePointManager começa a enfileirar solicitações antes de enviá-las. Suponha que o teu DefaultConnectionLimit esteja definido como 2 e o teu código faça 1.000 pedidos HTTP. Inicialmente, apenas 2 solicitações são permitidas através do sistema operacional. Os outros 998 pedidos estão na fila até que haja espaço para eles. O seu HttpClient pode expirar porque parece ter efetuado a solicitação, mas a solicitação nunca foi enviada pelo sistema operativo até ao servidor de destino. 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 Basic e superiores do Serviço de Aplicações.

Se o WebJob estiver sendo executado em um plano do 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 600. Se tiver um limite de conexão ilimitado no ServicePointManager, há uma maior probabilidade de que o limite de conexão da sandbox seja atingido e o site seja encerrado. Nesse caso, a configuração DefaultConnectionLimit para algo mais baixo, como 200, pode impedir que esse cenário ocorra 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 neste exemplo:

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 WebJobs dá suporte ao mesmo conjunto de gatilhos e vinculação que o Azure Functions usa. No SDK WebJobs, os gatilhos são específicos da função e não estão relacionados ao tipo de implantação WebJob. WebJobs que têm 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 blobs.

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 atributo QueueTrigger indica ao tempo de execução para chamar a função sempre que uma mensagem de fila aparecer em myqueue-items. O atributo Blob informa o tempo de execução para utilizar a mensagem de fila a fim de ler um blob no contentor 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 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 ativado no painel 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 :

[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 vinculação específico na seção "Pacotes" do artigo de referência do Azure Functions desse tipo de vinculação. Uma exceção é o gatilho e a vinculação de Arquivos (para o sistema de arquivos local), que o Azure Functions não suporta.

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 o método de extensão AddAzureStorage no método 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();
    }
}

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:

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 métodos de extensão AddTimers ou AddFiles.

Versão 2.x

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

  • 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 um método Use<binding> no objeto JobHostConfiguration. Por exemplo, se quiseres usar um gatilho de Timer, instala Microsoft.Azure.WebJobs.Extensions e chama UseTimers no método Main:

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 UseFiles.

Contexto de Execução

Em WebJobs, você pode vincular a uma ExecutionContext instância. Com essa ligação, você pode acessar 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 a ExecutionContext depende da sua versão do SDK.

Versão 3.x

Chame o método de extensão AddExecutionContextBinding no método 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();
    }
}

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. Você pode usar a associação para definir um ExecutionContext parâmetro em sua assinatura de função:

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 método Add<Binding> for chamado em ConfigureWebJobs.
  • Versão 2.x: Defina a configuração definindo propriedades num 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 ficheiro dehost.json projeto nas 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 Vinculação do Azure Cosmos DB.

Configuração de gatilho dos Hubs de Eventos do Azure (versão 3.x)

Este exemplo mostra como configurar o trigger do Event Hubs:

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 Vinculação de Hubs de Eventos.

Configuração do gatilho para 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 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 host.json referência 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 SendGrid vinculação.

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 informações, consulte 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, você pode usar o gatilho File para 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 atribuir um nome de fila ao atributo 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 (%):

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

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

Um resolvedor padrão 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, a ConfigurationManager instância usada requer o System.Configuration.ConfigurationManager pacote NuGet. 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:

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

Versão 3.x

Para configurar o resolvedor, utilize 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:

 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 diretamente o SDK WebJobs, pode-se escrever uma implementação personalizada que obtenha valores de substituição para espaços reservados a partir de qualquer fonte da 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 que tem 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. As seguintes informações estão em cada artigo de referência vinculativa. (Este exemplo é baseado em uma 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 atributo FunctionName.
  • 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, um algoritmo de sondagem ou 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: Desativar, Tempo Limite e Singleton

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

Desativar atributo

Use o Disable atributo para 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 1 (não específico a maiúsculas e True minúsculas), a função não será executada. Nesse cenário, o tempo de execução cria a mensagem de log Função 'Functions.TestJob' está desabilitada.

[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 Timeout atributo. O tempo limite faz com que a função seja cancelada após 15 segundos. Quando o atributo Timeout parâmetro throwOnError é definido como true, a invocação da função é encerrada, e uma exceção é lançada pelo SDK WebJobs quando o intervalo de tempo limite é excedido. O valor padrão de throwOnError é false. Quando o Timeout atributo é 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 Timeout atributo no nível da classe ou no nível do 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 Singleton atributo usa bloqueio distribuído para garantir que apenas 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

Para saber mais sobre como SingletonMode.Function funciona, consulte o repositório GitHub SingletonMode.

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 sejam 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 sequencialmente. A mensagem com a região Oeste corre em paralelo com as mensagens na 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 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 AddItem ou RemoveItem é executada 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 para implementar o bloqueio distribuído. Os blobs de arrendamento usados por Singleton podem ser encontrados no azure-webjobs-host contentor na AzureWebJobsStorage conta de armazenamento sob o caminho "locks". Por exemplo, o caminho do blob de arrendamento 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 encerramento gracioso.

Múltiplas instâncias

Se a sua aplicação web estiver a funcionar em várias instâncias, um WebJob contínuo será executado em cada instância, à escuta de gatilhos e chamando funções. As várias ligações de acionadores são projetadas para compartilhar eficientemente o trabalho de forma colaborativa entre instâncias, permitindo que a escalabilidade para mais instâncias possibilite o manuseio de maior carga.

Embora alguns gatilhos possam resultar em processamento duplo, os gatilhos relacionados ao armazenamento de fila e blob impedem automaticamente que uma função processe uma mensagem de fila ou um 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ções (pré-visualização) fornecem uma maneira de personalizar o pipeline de execução dos WebJobs usando a sua própria lógica. Esses 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 que você use a estrutura de 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 valores e associados CategoryLevel . LogLevel é uma enumeração e o código inteiro indica importância relativa:

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

Você pode filtrar independentemente cada categoria para um valor específico LogLevel . Por exemplo, talvez queiras ver todos os registos de processamento de ativação de blob, mas apenas Error ou níveis superiores para todo o resto.

Versão 3.x

Versão 3. x do SDK depende da filtragem incorporada no .NET Core. Use a LogCategories classe para definir categorias para funções, gatilhos ou usuários específicos. A LogCategories classe também define filtros para estados de host específicos, como Startup e Results, para que você possa ajustar a saída de log. Se nenhuma correspondência for encontrada nas categorias definidas, o filtro retornará ao Default valor ao determinar se a mensagem deve ser filtrada.

LogCategories requer a seguinte using declaração:

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 (equivalentes a Host.Results na versão 2.x) são filtradas ao nível Error. O filtro compara a categoria atual com todos os níveis registrados na LogCategories instância e escolhe a correspondência mais longa. Assim, o nível registado para Debug corresponder a Host.Triggers ou Host.Triggers.Queue. Você pode controlar 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 propriedade Default com um valor inicial de Information, o que significa que as mensagens nos níveis Information, Warning, Error ou Critical são registadas, mas as mensagens nos níveis Debug 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 determinar se a mensagem deve ser filtrada.

O exemplo a seguir constrói um filtro que, por padrão, filtra todos os logs no Warning nível. As categorias Function e Host.Results são filtradas ao nível Error. O LogCategoryFilter compara a categoria atual com todos os inscritos CategoryLevels e escolhe a partida mais longa. Assim, o nível registado para Debug corresponder a Host.Triggers ou Host.Triggers.Queue. Você pode controlar 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 registos 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;

Você pode usar a seguinte implementação personalizada de ITelemetryInitializer para adicionar sua própria ITelemetry instância ao padrão TelemetryConfiguration.

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

Chame ConfigureServices no construtor para adicionar uma instância ITelemetryInitializer personalizada 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 code 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 TelemetryConfiguration é construído, todos os tipos registrados de ITelemetryInitializer são incluídos. Para obter mais informações, consulte API do Application Insights para eventos e métricas personalizados.

Na versão 3.x, não tens de esvaziar TelemetryClient quando o host parar. O sistema de injeção de dependência do .NET Core descarta automaticamente a instância registrada ApplicationInsightsLoggerProvider, que limpa o TelemetryClient.

Versão 2.x

Na versão 2.x, a instância TelemetryClient criada internamente pelo fornecedor do Application Insights para o SDK do WebJobs utiliza ServerTelemetryChannel. Quando o ponto de extremidade do Application Insights não está disponível ou está a limitar as solicitações de entrada, este canal salva as solicitações no sistema de ficheiros da aplicação web e as reenvia posteriormente.

TelemetryClient é criado por uma classe que implementa ITelemetryClientFactory. Por padrão, essa classe é DefaultTelemetryClientFactory.

Se quiser modificar qualquer parte do pipeline do Application Insights, você pode fornecer sua própria instância do ITelemetryClientFactory. Em seguida, o host usa a sua classe para construir TelemetryClient. 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. Nesse cenário, 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);

Conteúdo relacionado

Este artigo fornece 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.