Gatilho do SQL do Azure para Functions

Observação

Nas funções do plano de consumo, o dimensionamento automático não tem suporte para o gatilho SQL. Se o processo de dimensionamento automático interromper a função, todo o processamento de eventos será interrompido e ele precisará ser reiniciado manualmente.

Use planos Premium ou dedicados para colocar benefícios em escala com o gatilho do SQL.

O gatilho do SQL do Azure usa a funcionalidade de controle de alterações do SQL para monitorar uma tabela SQL para alterações e disparar uma função quando uma linha é criada, atualizada ou excluída. Para obter detalhes de configuração para controle de alterações para uso com o gatilho do SQL do Azure, consulte Configurar o controle de alterações. Para obter informações sobre detalhes de instalação da extensão de SQL do Azure para o Azure Functions, consulte a Visão geral da associação do SQL.

As decisões de ampliação de armazenamento do gatilho do SQL do Azure para os planos Consumo e Premium são tomadas por meio da ampliação baseada no destino. Para obter mais informações, consulte Ampliação baseada em destino.

Visão geral da funcionalidade

A associação do gatilho do SQL do Azure usa um loop de sondagem para verificar se há alterações, disparando a função de usuário quando elas são detectadas. Em um nível elevado, o loop é mais ou menos assim:

while (true) {
    1. Get list of changes on table - up to a maximum number controlled by the Sql_Trigger_MaxBatchSize setting
    2. Trigger function with list of changes
    3. Wait for delay controlled by Sql_Trigger_PollingIntervalMs setting
}

As alterações são processadas na ordem em que foram feitas, com as alterações mais antigas sendo processadas primeiro. Algumas observações sobre o processamento de alterações:

  1. Se as alterações forem feitas em diversas linhas ao mesmo tempo, a ordem exata em que serão enviadas para a função se baseará na ordem retornada pela função CHANGETABLE
  2. As alterações são "agrupadas em lote" para uma linha. Se várias alterações forem feitas em uma linha entre cada iteração do loop, apenas uma entrada de alteração mostrando a diferença entre o último estado processado e o estado atual existirá para essa linha
  3. Se forem feitas alterações em um conjunto de linhas e, em seguida, outro conjunto de alterações for feito para metade dessas mesmas linhas, a metade que não foi alterada pela segunda vez será processada primeiro. Essa lógica de processamento se deve à observação acima, com as alterações sendo agrupadas em lote: o gatilho verá apenas a "última" alteração feita e a usará para a ordem em que as alterações serão processadas

Para obter mais informações sobre o acompanhamento de alterações e como ele é usado por aplicativos como os gatilhos de SQL do Azure, confira trabalhar com o acompanhamento de alterações.

Exemplo de uso

Há mais exemplos para o gatilho do SQL do Azure disponíveis no Repositório do GitHub.

O exemplo refere-se a uma classe ToDoItem e a uma tabela de banco de dados correspondente:

namespace AzureSQL.ToDo
{
    public class ToDoItem
    {
        public Guid Id { get; set; }
        public int? order { get; set; }
        public string title { get; set; }
        public string url { get; set; }
        public bool? completed { get; set; }
    }
}
CREATE TABLE dbo.ToDo (
    [Id] UNIQUEIDENTIFIER PRIMARY KEY,
    [order] INT NULL,
    [title] NVARCHAR(200) NOT NULL,
    [url] NVARCHAR(200) NOT NULL,
    [completed] BIT NOT NULL
);

O controle de alterações está habilitado no banco de dados e na tabela:

ALTER DATABASE [SampleDatabase]
SET CHANGE_TRACKING = ON
(CHANGE_RETENTION = 2 DAYS, AUTO_CLEANUP = ON);

ALTER TABLE [dbo].[ToDo]
ENABLE CHANGE_TRACKING;

O gatilho do SQL se vincula a uma IReadOnlyList<SqlChange<T>>, uma lista de objetos de SqlChange, cada um com duas propriedades:

  • Item: o item que foi alterado. O tipo do item deve seguir o esquema de tabela, conforme visto na classe ToDoItem.
  • Operação: um valor de enumeração SqlChangeOperation. Os valores possíveis são Insert, Update e Delete.

O exemplo a seguir mostra uma função C# que é invocada quando há alterações na tabela ToDo:

using System;
using System.Collections.Generic;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Extensions.Sql;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;


namespace AzureSQL.ToDo
{
    public static class ToDoTrigger
    {
        [Function("ToDoTrigger")]
        public static void Run(
            [SqlTrigger("[dbo].[ToDo]", "SqlConnectionString")]
            IReadOnlyList<SqlChange<ToDoItem>> changes,
            FunctionContext context)
        {
            var logger = context.GetLogger("ToDoTrigger");
            foreach (SqlChange<ToDoItem> change in changes)
            {
                ToDoItem toDoItem = change.Item;
                logger.LogInformation($"Change operation: {change.Operation}");
                logger.LogInformation($"Id: {toDoItem.Id}, Title: {toDoItem.title}, Url: {toDoItem.url}, Completed: {toDoItem.completed}");
            }
        }
    }
}

Exemplo de uso

Há mais exemplos para o gatilho do SQL do Azure disponíveis no Repositório do GitHub.

O exemplo refere-se a uma classe ToDoItem, uma classe SqlChangeToDoItem e uma enumeração SqlChangeOperation e a uma tabela de banco de dados correspondente:

Em um arquivo ToDoItem.java separado:

package com.function;
import java.util.UUID;

public class ToDoItem {
    public UUID Id;
    public int order;
    public String title;
    public String url;
    public boolean completed;

    public ToDoItem() {
    }

    public ToDoItem(UUID Id, int order, String title, String url, boolean completed) {
        this.Id = Id;
        this.order = order;
        this.title = title;
        this.url = url;
        this.completed = completed;
    }
}

Em um arquivo SqlChangeToDoItem.java separado:

package com.function;

public class SqlChangeToDoItem {
    public ToDoItem item;
    public SqlChangeOperation operation;

    public SqlChangeToDoItem() {
    }

    public SqlChangeToDoItem(ToDoItem Item, SqlChangeOperation Operation) {
        this.Item = Item;
        this.Operation = Operation;
    }
}

Em um arquivo SqlChangeOperation.java separado:

package com.function;

import com.google.gson.annotations.SerializedName;

public enum SqlChangeOperation {
    @SerializedName("0")
    Insert,
    @SerializedName("1")
    Update,
    @SerializedName("2")
    Delete;
}
CREATE TABLE dbo.ToDo (
    [Id] UNIQUEIDENTIFIER PRIMARY KEY,
    [order] INT NULL,
    [title] NVARCHAR(200) NOT NULL,
    [url] NVARCHAR(200) NOT NULL,
    [completed] BIT NOT NULL
);

O controle de alterações está habilitado no banco de dados e na tabela:

ALTER DATABASE [SampleDatabase]
SET CHANGE_TRACKING = ON
(CHANGE_RETENTION = 2 DAYS, AUTO_CLEANUP = ON);

ALTER TABLE [dbo].[ToDo]
ENABLE CHANGE_TRACKING;

O gatilho do SQL se vincula a um SqlChangeToDoItem[], a uma lista de objetos de SqlChangeToDoItem, cada um com duas propriedades:

  • Item: o item que foi alterado. O tipo do item deve seguir o esquema de tabela, conforme visto na classe ToDoItem.
  • Operação: um valor de enumeração SqlChangeOperation. Os valores possíveis são Insert, Update e Delete.

O exemplo a seguir mostra uma função Java que é invocada quando há alterações na tabela ToDo:

package com.function;

import com.microsoft.azure.functions.ExecutionContext;
import com.microsoft.azure.functions.annotation.FunctionName;
import com.microsoft.azure.functions.sql.annotation.SQLTrigger;
import com.function.Common.SqlChangeToDoItem;
import com.google.gson.Gson;

import java.util.logging.Level;

public class ProductsTrigger {
    @FunctionName("ToDoTrigger")
    public void run(
            @SQLTrigger(
                name = "todoItems",
                tableName = "[dbo].[ToDo]",
                connectionStringSetting = "SqlConnectionString")
                SqlChangeToDoItem[] todoItems,
            ExecutionContext context) {

        context.getLogger().log(Level.INFO, "SQL Changes: " + new Gson().toJson(changes));
    }
}

Exemplo de uso

Há mais exemplos para o gatilho do SQL do Azure disponíveis no Repositório do GitHub.

Os exemplos se referem a uma tabela ToDoItem de banco de dados:

CREATE TABLE dbo.ToDo (
    [Id] UNIQUEIDENTIFIER PRIMARY KEY,
    [order] INT NULL,
    [title] NVARCHAR(200) NOT NULL,
    [url] NVARCHAR(200) NOT NULL,
    [completed] BIT NOT NULL
);

O controle de alterações está habilitado no banco de dados e na tabela:

ALTER DATABASE [SampleDatabase]
SET CHANGE_TRACKING = ON
(CHANGE_RETENTION = 2 DAYS, AUTO_CLEANUP = ON);

ALTER TABLE [dbo].[ToDo]
ENABLE CHANGE_TRACKING;

O gatilho do SQL se vincula a uma todoChanges, uma lista de objetos, cada um com duas propriedades:

  • Item: o item que foi alterado. A estrutura do item seguirá o esquema da tabela.
  • operação: os valores possíveis são Insert, Update e Delete.

O exemplo a seguir mostra uma função do PowerShell que é invocada quando há alterações na tabela ToDo.

Veja a seguir os dados de associação no arquivo function.json:

{
    "name": "todoChanges",
    "type": "sqlTrigger",
    "direction": "in",
    "tableName": "dbo.ToDo",
    "connectionStringSetting": "SqlConnectionString"
}

A seção configuração explica essas propriedades.

Veja o seguinte exemplo de código do PowerShell para a função no arquivo run.ps1:

using namespace System.Net

param($todoChanges)
# The output is used to inspect the trigger binding parameter in test methods.
# Use -Compress to remove new lines and spaces for testing purposes.
$changesJson = $todoChanges | ConvertTo-Json -Compress
Write-Host "SQL Changes: $changesJson"

Exemplo de uso

Há mais exemplos para o gatilho do SQL do Azure disponíveis no Repositório do GitHub.

Os exemplos se referem a uma tabela ToDoItem de banco de dados:

CREATE TABLE dbo.ToDo (
    [Id] UNIQUEIDENTIFIER PRIMARY KEY,
    [order] INT NULL,
    [title] NVARCHAR(200) NOT NULL,
    [url] NVARCHAR(200) NOT NULL,
    [completed] BIT NOT NULL
);

O controle de alterações está habilitado no banco de dados e na tabela:

ALTER DATABASE [SampleDatabase]
SET CHANGE_TRACKING = ON
(CHANGE_RETENTION = 2 DAYS, AUTO_CLEANUP = ON);

ALTER TABLE [dbo].[ToDo]
ENABLE CHANGE_TRACKING;

O gatilho do SQL se vincula a todoChanges, a uma lista de objetos, cada um com duas propriedades:

  • Item: o item que foi alterado. A estrutura do item seguirá o esquema da tabela.
  • operação: os valores possíveis são Insert, Update e Delete.

O exemplo a seguir mostra uma função JavaScript que é invocada quando há alterações na tabela ToDo.

Veja a seguir os dados de associação no arquivo function.json:

{
    "name": "todoChanges",
    "type": "sqlTrigger",
    "direction": "in",
    "tableName": "dbo.ToDo",
    "connectionStringSetting": "SqlConnectionString"
}

A seção configuração explica essas propriedades.

Veja o seguinte exemplo de código do JavaScript para a função no arquivo index.js:

module.exports = async function (context, todoChanges) {
    context.log(`SQL Changes: ${JSON.stringify(todoChanges)}`)
}

Exemplo de uso

Há mais exemplos para o gatilho do SQL do Azure disponíveis no Repositório do GitHub.

Os exemplos se referem a uma tabela ToDoItem de banco de dados:

CREATE TABLE dbo.ToDo (
    [Id] UNIQUEIDENTIFIER PRIMARY KEY,
    [order] INT NULL,
    [title] NVARCHAR(200) NOT NULL,
    [url] NVARCHAR(200) NOT NULL,
    [completed] BIT NOT NULL
);

O controle de alterações está habilitado no banco de dados e na tabela:

ALTER DATABASE [SampleDatabase]
SET CHANGE_TRACKING = ON
(CHANGE_RETENTION = 2 DAYS, AUTO_CLEANUP = ON);

ALTER TABLE [dbo].[ToDo]
ENABLE CHANGE_TRACKING;

O gatilho do SQL se vincula a uma variável todoChanges, uma lista de objetos, cada um com duas propriedades:

  • Item: o item que foi alterado. A estrutura do item seguirá o esquema da tabela.
  • operação: os valores possíveis são Insert, Update e Delete.

O exemplo a seguir mostra uma função Python que é invocada quando há alterações na tabela ToDo.

A seguir está o código python de exemplo para o arquivo function_app.py:

import json
import logging
import azure.functions as func
from azure.functions.decorators.core import DataType

app = func.FunctionApp()

@app.function_name(name="ToDoTrigger")
@app.sql_trigger(arg_name="todo",
                        table_name="ToDo",
                        connection_string_setting="SqlConnectionString")
def todo_trigger(todo: str) -> None:
    logging.info("SQL Changes: %s", json.loads(todo))

Atributos

A biblioteca C# usa o atributo SqlTrigger para declarar o gatilho do SQL na função, que tem as seguintes propriedades:

Propriedade de atributo Descrição
TableName Obrigatórios. O nome da tabela monitorada pelo gatilho.
ConnectionStringSetting Obrigatórios. O nome de uma configuração de aplicativo que contém a cadeia de conexão para o banco de dados contendo a tabela monitorada para detectar alterações. O nome da configuração da cadeia de conexão corresponde à configuração do aplicativo (em local.settings.json para desenvolvimento local) que contém a local.settings.json para a instância de SQL do Azure ou do SQL Server.
LeasesTableName Opcional. Nome da tabela usado para armazenar concessões. Se não estiver especificado, o nome da tabela de concessões será Leases_{FunctionId}_{TableId}. Mais informações sobre como isso é gerado podem ser encontradas aqui.

Anotações

Na biblioteca de runtime de funções Java, use a anotação @SQLTrigger (com.microsoft.azure.functions.sql.annotation.SQLTrigger) nos parâmetros cujo valor viria de um SQL do Azure. Essa anotação dá suporte aos seguintes elementos:

Elemento Descrição
name Obrigatórios. O nome do parâmetro ao qual o gatilho se associa.
tableName Obrigatórios. O nome da tabela monitorada pelo gatilho.
connectionStringSetting Obrigatórios. O nome de uma configuração de aplicativo que contém a cadeia de conexão para o banco de dados contendo a tabela monitorada para detectar alterações. O nome da configuração da cadeia de conexão corresponde à configuração do aplicativo (em local.settings.json para desenvolvimento local) que contém a local.settings.json para a instância de SQL do Azure ou do SQL Server.
LeasesTableName Opcional. Nome da tabela usado para armazenar concessões. Se não estiver especificado, o nome da tabela de concessões será Leases_{FunctionId}_{TableId}. Mais informações sobre como isso é gerado podem ser encontradas aqui.

Configuração

A tabela a seguir explica as propriedades de configuração de associação que você define no arquivo function.json.

Propriedade function.json Descrição
name Obrigatórios. O nome do parâmetro ao qual o gatilho se associa.
tipo Obrigatórios. Deve ser definido como sqlTrigger.
direction Obrigatórios. Deve ser definido como in.
tableName Obrigatórios. O nome da tabela monitorada pelo gatilho.
connectionStringSetting Obrigatórios. O nome de uma configuração de aplicativo que contém a cadeia de conexão para o banco de dados contendo a tabela monitorada para detectar alterações. O nome da configuração da cadeia de conexão corresponde à configuração do aplicativo (em local.settings.json para desenvolvimento local) que contém a local.settings.json para a instância de SQL do Azure ou do SQL Server.
LeasesTableName Opcional. Nome da tabela usado para armazenar concessões. Se não estiver especificado, o nome da tabela de concessões será Leases_{FunctionId}_{TableId}. Mais informações sobre como isso é gerado podem ser encontradas aqui.

Configuração opcional

As configurações opcionais a seguir podem ser definidas para o gatilho SQL para desenvolvimento local ou para implantações de nuvem.

host. JSON

Esta seção descreve as definições de configuração disponíveis para a associação nas versões 2.x e superiores. As configurações no arquivo host.json se aplicam a todas as funções em uma instância do aplicativo de funções. O arquivo host.json de exemplo abaixo contém apenas as configurações das versões 2.x e superiores para a associação. Para saber mais sobre as definições de configuração do aplicativo de funções nas versões 2.x e superiores, confira a referência de host.json para o Azure Functions.

Configuração Padrão Descrição
MaxBatchSize 100 O número máximo de alterações processadas com cada iteração do loop de gatilho antes de serem enviadas para a função acionada.
PollingIntervalMs 1000 O atraso em milissegundos entre o processamento de cada lote de alterações. (1000 ms é 1 segundo)
MaxChangesPerWorker 1000 O limite superior do número de alterações pendentes na tabela do usuário permitidas por trabalho do aplicativo. Se a contagem de alterações exceder esse limite, isso poderá resultar em uma expansão. A configuração só se aplica aos Aplicativos de Função do Azure com escalabilidade orientada por tempo de execução habilitada.

Exemplo host.json arquivo

Aqui está um exemplo host.json arquivo com as configurações opcionais:

{
  "version": "2.0",
  "extensions": {
      "Sql": {
        "MaxBatchSize": 300,
        "PollingIntervalMs": 1000,
        "MaxChangesPerWorker": 100
      }
  },
  "logging": {
    "applicationInsights": {
      "samplingSettings": {
        "isEnabled": true,
        "excludedTypes": "Request"
      }
    },
    "logLevel": {
      "default": "Trace"
    }
  }
}

local.setting.json

O arquivo local.settings.json armazena as configurações do aplicativo e aquelas usadas pelas ferramentas de desenvolvimento locais. As configurações no arquivo local.settings.json são usadas somente ao executar projetos localmente. Ao publicar seu projeto no Azure, adicione também as configurações necessárias às configurações do aplicativo para o aplicativo de funções.

Importante

Como o local.settings.json pode conter segredos, como cadeias de conexão, você nunca deve armazená-lo em um repositório remoto. As ferramentas que dão suporte ao Functions fornecem maneiras de sincronizar as configurações do aplicativo de funções no qual seu projeto está implantado com aquelas no arquivo local.settings.json.

Configuração Padrão Descrição
Sql_Trigger_BatchSize 100 O número máximo de alterações processadas com cada iteração do loop de gatilho antes de serem enviadas para a função acionada.
Sql_Trigger_PollingIntervalMs 1000 O atraso em milissegundos entre o processamento de cada lote de alterações. (1000 ms é 1 segundo)
Sql_Trigger_MaxChangesPerWorker 1000 O limite superior do número de alterações pendentes na tabela do usuário permitidas por trabalho do aplicativo. Se a contagem de alterações exceder esse limite, isso poderá resultar em uma expansão. A configuração só se aplica aos Aplicativos de Função do Azure com escalabilidade orientada por tempo de execução habilitada.

Exemplo local.settings.json arquivo

Aqui está um exemplo local.settings.json arquivo com as configurações opcionais:

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet",
    "SqlConnectionString": "",
    "Sql_Trigger_MaxBatchSize": 300,
    "Sql_Trigger_PollingIntervalMs": 1000,
    "Sql_Trigger_MaxChangesPerWorker": 100
  }
}

Configurar o controle de alterações (obrigatório)

Configurar o controle de alterações para uso com o gatilho do SQL do Azure requer duas etapas. Essas etapas podem ser concluídas em qualquer ferramenta do SQL que dê suporte à execução de consultas, incluindo o Visual Studio Code, o Azure Data Studio ou o SQL Server Management Studio.

  1. Habilite o controle de alterações no banco de dados SQL, substituindo your database name pelo nome do banco de dados em que a tabela a ser monitorada está localizada:

    ALTER DATABASE [your database name]
    SET CHANGE_TRACKING = ON
    (CHANGE_RETENTION = 2 DAYS, AUTO_CLEANUP = ON);
    

    A opção CHANGE_RETENTION especifica o período de tempo que o controle de alterações mantém as informações (histórico de alterações). A retenção do histórico de alterações pelo banco de dados SQL pode afetar a funcionalidade de disparo. Por exemplo, se a Função do Azure ficar desativada por vários dias e, em seguida, for retomada, o banco de dados conterá as alterações que ocorreram nos últimos dois dias no exemplo de configuração acima.

    A opção AUTO_CLEANUP é usada para habilitar ou desabilitar a tarefa de limpeza que remove informações antigas de controle de alterações. Se um problema temporário que impede a execução do gatilho, desativar a limpeza automática, pode ser útil para pausar a remoção de informações anteriores ao período de retenção até que o problema seja resolvido.

    Mais informações sobre opções de controle de alterações estão disponíveis na documentação do SQL.

  2. Habilite o controle de alterações na tabela, substituindo your table name pelo nome da tabela a ser monitorada (alterando o esquema, se apropriado):

    ALTER TABLE [dbo].[your table name]
    ENABLE CHANGE_TRACKING;
    

    O gatilho precisa ter acesso de leitura na tabela que está sendo monitorada para alterações e para as tabelas do sistema de controle de alterações. Cada gatilho de função tem uma tabela de acompanhamento de alterações associada e uma tabela de concessões em um esquema az_func. Se ainda não existirem, essas tabelas serão criadas pelo gatilho. Mais informações sobre essas estruturas de dados estão disponíveis na documentação da biblioteca de associação do SQL do Azure.

Habilitar a escala controlada por runtime

Opcionalmente, as funções podem ser dimensionadas automaticamente com base na quantidade de alterações pendentes a serem processadas na tabela do usuário. Para permitir que suas funções sejam dimensionadas corretamente no plano Premium ao usar gatilhos do SQL, você precisa habilitar o monitoramento de escala por runtime.

No portal do Azure, em seu aplicativo de funções, escolha Configuração e, na guia Configurações de runtime de funções, altere o Monitoramento de escala do Runtime para Ativo.

Captura de tela do painel do portal do Azure para habilitar escala por runtime.

Suporte à repetição

Mais informações sobre tabelas de concessões e o suporte à repetição do gatilho SQL estão disponíveis no repositório do GitHub.

Tentativas de inicialização

Se ocorrer uma exceção durante a inicialização, o runtime do host tentará reiniciar automaticamente o ouvinte de gatilho com uma estratégia de retirada exponencial. Essas tentativas continuam até que o ouvinte seja iniciado com sucesso ou a inicialização seja cancelada.

Repetições de conexão interrompida

Se a função for iniciada com sucesso, mas um erro fizer com que a conexão seja interrompida (como, por exemplo, se o servidor sair do ar), a função continuará tentando reabrir a conexão até que a função seja impedida ou a conexão seja bem-sucedida. Se for restabelecida com sucesso, a conexão irá retomar as alterações de processamento de onde parou.

Observe que essas tentativas estão fora da lógica interna de repetição de conexão ociosa que o SqlClient tem, que pode ser configurada com as ConnectRetryCount opções de cadeia de conexão e ConnectRetryInterval . As repetições de conexão ociosa integradas são tentadas primeiro e, se não conseguirem se reconectar, a vinculação do gatilho tentará restabelecer a conexão propriamente dita.

Repetições de exceção de função

Se ocorrer uma exceção na função de usuário ao processar alterações, o lote de linhas sendo processado no momento tentará novamente em 60 segundos. Outras alterações são processadas normalmente durante esse período, mas as linhas do lote que causaram a exceção são ignoradas até que o período de tempo limite tenha decorrido.

Se a execução da função falhar cinco vezes seguidas para uma determinada linha, essa linha será completamente ignorada para todas as alterações futuras. Como as linhas em um lote não são determinísticas, as linhas em um lote com falha podem acabar em lotes diferentes em chamadas subsequentes. Isso significa que nem todas as linhas no lote com falha serão necessariamente ignoradas. Se outras linhas no lote foram as que causaram a exceção, as linhas "boas" podem acabar em um lote diferente que não falha em chamadas futuras.

Próximas etapas