Início Rápido: Criar um aplicativo Durable Functions que usa o provedor de armazenamento MSSQL

Use Durable Functions, um recurso de Azure Functions, para gravar funções com estado em um ambiente sem servidor. Durable Functions gerencia o estado, os pontos de verificação e as reinicializações em seu aplicativo.

O Durable Functions dá suporte a vários provedores de armazenamento, também conhecidos como back-ends, para armazenar o estado de execução da orquestração e da entidade. Neste início rápido, você cria um aplicativo Durable Functions que usa o provedor de armazenamento Microsoft SQL Server (MSSQL com Visual Studio Code.

Este início rápido cria um aplicativo .NET (modelo isolado) para fins de demonstração. Os conceitos se aplicam a outras linguagens de maneiras semelhantes.

Dica

Se você já tiver uma instância de SQL Server e quiser ignorar a instalação do banco de dados local, vá diretamente para Add SQL cadeia de conexão para local.settings.json.

Observação

Não há suporte para a migração de dados do hub de tarefas entre provedores de armazenamento. Os aplicativos de funções que têm dados de runtime existentes começam com um hub de tarefas novo e vazio depois de alternar para o back-end do MSSQL.

Pré-requisitos

Para concluir este guia de início rápido, você precisa:

Criar um projeto de Azure Functions

Em Visual Studio Code, crie um projeto de Azure Functions local.

  1. No menu Exibir selecione menu Paleta de Comandos (ou selecione Ctrl+Shift+P).

  2. No prompt (>), insira e selecione Azure Functions: Criar Novo Projeto.

    Screenshot da paleta de comandos em Visual Studio Code mostrando a opção de criar um projeto do Functions.

  3. Selecione Procurar. Na caixa de diálogo Selecionar Pasta, vá para uma pasta a ser usada em seu projeto e escolha Selecionar.

  4. Todos os prompts, selecione ou insira os valores a seguir:

    Rápido Ação Descrição
    Selecione uma linguagem para o seu projeto de aplicativo de funções Selecione .NET Cria um projeto local do C# Functions
    Selecione um runtime .NET Selecione .NET 8.0 isolado. Cria um projeto do Functions que dá suporte a .NET 8 em execução em um processo de trabalho isolado e no Azure Functions Runtime 4.0.
    Selecione um modelo para a primeira função do projeto Selecione Durable Functions Orchestration. Cria uma orquestração do Durable Functions.
    Escolher um tipo de armazenamento durável Selecione MSSQL. Seleciona o provedor de armazenamento MSSQL.
    Forneça um nome para a função Inserir HelloOrchestration. Um nome para a função de orquestração.
    Forneça um namespace Inserir Company.Function. Um namespace da classe gerada.
    Selecione como deseja abrir o projeto Selecione Abrir na janela atual. Abre Visual Studio Code na pasta selecionada.

Visual Studio Code instala Azure Functions Core Tools se for necessário criar o projeto. Ele também cria o projeto de aplicativo de funções em uma pasta. Este projeto contém os arquivos de configuração host.json e local.settings.json.

Outro arquivo, HelloOrchestration.cs, contém os blocos de construção básicos de um aplicativo Durable Functions:

Método Descrição
HelloOrchestration Define a orquestração do aplicativo Durable Functions. Nesse caso, a orquestração é iniciada, cria uma lista e depois adiciona o resultado de três chamadas de função à lista. Quando as três chamadas de função são finalizadas, ela retorna a lista.
SayHello Um aplicativo de funções simples que retorna hello. Esta função contém a lógica de negócios que está orquestrada.
HelloOrchestration_HttpStart Uma função disparada por HTTP que inicia uma instância da orquestração e retorna uma resposta de verificação de status.

Para obter mais informações sobre essas funções, consulte tipos e recursos do Durable Functions.

Configurar seu banco de dados

Este início rápido usa uma imagem do Docker SQL Server. Para obter alternativas (SQL Server Express, Banco de Dados SQL do Azure ou uma instância local), consulte a visão geral dos provedores storage.

Observação

Se você já tiver um banco de dados compatível com MSSQL, pule para Adicionar a cadeia de conexão SQL a local.settings.json.

Configurar sua instância de SQL Server local baseada no Docker

Use os comandos do PowerShell a seguir para configurar um banco de dados de SQL Server local no Docker. Você pode instalar o PowerShell em Windows, macOS ou Linux.

# primary parameters
$pw        = "yourStrong(!)Password"
$edition   = "Developer"
$port      = 1433
$tag       = "2019-latest"
$dbname    = "DurableDB"
$collation = "Latin1_General_100_BIN2_UTF8"

# pull the image from the Microsoft container registry
docker pull mcr.microsoft.com/mssql/server:$tag

# run the image and provide some basic setup parameters
docker run --name mssql-server -e 'ACCEPT_EULA=Y' -e "MSSQL_SA_PASSWORD=$pw" -e "MSSQL_PID=$edition" -p ${port}:1433 -d mcr.microsoft.com/mssql/server:$tag

# wait a few seconds for the container to start...

# create the database with strict binary collation
docker exec -it mssql-server /opt/mssql-tools/bin/sqlcmd -S . -U sa -P "$pw" -Q "CREATE DATABASE [$dbname] COLLATE $collation"

# if sqlcmd is in the mssql-tools18 folder
# docker exec -it mssql-server /opt/mssql-tools18/bin/sqlcmd -C -S . -U sa -P "$pw" -Q "CREATE DATABASE [$dbname] COLLATE $collation"

Agora você deve ter um SQL Server local em execução no Docker e ouvindo na porta 1433. Se a porta 1433 entrar em conflito com outro serviço, execute novamente esses comandos depois de alterar a variável $port para um valor diferente.

Para validar a instalação do banco de dados, consulte seu novo banco de dados SQL:

docker exec -it mssql-server /opt/mssql-tools/bin/sqlcmd -S . -U sa -P "$pw" -Q "SELECT name FROM sys.databases"

Se a instalação do banco de dados tiver sido concluída com sucesso, o nome do banco de dados (por exemplo, DurableDB) irá aparecer no resultado da linha de comando:

name

--------------------------------------------------------------
master

tempdb

model

msdb

DurableDB

Observação

Para parar e excluir um contêiner em execução, você poderá usar docker stop <containerName> e docker rm <containerName>, respectivamente. Você poderá usar esses comandos para recriar e parar o contêiner quando concluir esse início rápido. Para obter mais ajuda, execute o docker --help.

Solução de problemas

Se você encontrar "Resposta de erro do daemon: falha no exec do runtime do OCI" ao executar docker exec para criar o banco de dados, é provável que a pasta /opt/mssql-tools/bin/sqlcmd não exista. Abra o Docker Desktop, selecione seu contêiner SQL Server Docker, selecione Arquivos e procure a pasta mssql-tools. Verifique se essa pasta tem um nome diferente, como /opt/mssql-tools18/bin/sqlcmd. Atualize o comando adequadamente.

No Driver ODBC 18 para SQL Server, a opção criptografar conexão é definida como true por padrão. Se você encontrar "error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed:self signed certificate" ao executar docker exec para realizar operações de banco de dados, acrescente -C, que é equivalente à opção ADO.net TRUSTSERVERCERTIFICATE = true.

Adicionar string de conexão SQL ao local.settings.json

O back-end do MSSQL precisa de uma cadeia de conexão para acessar seu banco de dados. Como obter um cadeia de conexão depende principalmente do provedor de servidor MSSQL específico.

Se você usar os comandos anteriores do Docker sem alterar parâmetros, seu cadeia de conexão será:

Server=localhost,1433;Database=DurableDB;User Id=sa;Password=yourStrong(!)Password;

Em local.settings.json, atribua a cadeia de conexão da instância do SQL Server baseada no Docker a SQLDB_Connection. Essa variável foi adicionada por Visual Studio Code quando você escolheu o MSSQL como o back-end do aplicativo Durable Functions:

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true", 
    "SQLDB_Connection": "Server=localhost,1433;Database=DurableDB;User Id=sa;Password=yourStrong(!)Password;",
    "FUNCTIONS_WORKER_RUNTIME": "<dependent on your programming language>"
  }
}

Testar localmente

Abra uma janela de terminal na pasta raiz do aplicativo e execute azurite start. O Azurite é o emulador de Armazenamento do Azure, que é necessário para executar qualquer aplicativo de funções.

Abra outra janela do terminal na pasta raiz do aplicativo e inicie o aplicativo de funções executando func host start.

  1. Na janela do terminal, copie o endpoint de URL da função acionada por HTTP.

    Screenshot da janela de saída local do Azure Functions mostrando o ponto de extremidade da URL da função acionada por HTTP.

  2. Use uma ferramenta de teste HTTP para enviar uma solicitação HTTP POST ao ponto de extremidade da URL.

    A resposta é o resultado inicial da função HTTP. Isso informa que a orquestração do Durable Functions foi iniciada com êxito. Ela ainda não exibe o resultado final da orquestração. A resposta inclui algumas URLs úteis.

  3. Copie o valor da URL para statusQueryGetUri, cole-o na barra de endereço do seu navegador e execute a solicitação. Como alternativa, você também pode continuar a usar a ferramenta de teste HTTP para emitir a solicitação GET.

    A solicitação consulta a instância de orquestração do status. Você deve ver que a instância foi concluída e que ela inclui as saídas ou os resultados do aplicativo Durable Functions como neste exemplo:

    {
        "name":"HelloCities",
        "instanceId":"7f99f9474a6641438e5c7169b7ecb3f2",
        "runtimeStatus":"Completed",
        "input":null,
        "customStatus":null,
        "output":"Hello, Tokyo! Hello, London! Hello, Seattle!",
        "createdTime":"2023-01-31T18:48:49Z",
        "lastUpdatedTime":"2023-01-31T18:48:56Z"
    }
    

Executar seu aplicativo em Azure (opcional)

As seções anteriores completam o Início Rápido local. As seções a seguir percorrem a implantação em Azure, o que requer recursos e configurações adicionais.

Importante

Se o aplicativo estiver hospedado no Plano Consumo Flexível, a autenticação de identidade gerenciada para Banco de Dados SQL do Azure não será compatível. Em vez disso, use uma cadeia de conexão com autenticação SQL. Para obter suporte de identidade gerenciada com um plano sem servidor, considere usar o Agendador de Tarefas Duráveis.

Para executar seu aplicativo no Azure, você precisa criar vários recursos. Para uma limpeza conveniente posteriormente, crie todos os recursos no mesmo grupo de recursos.

Criar um banco de dados SQL do Azure

Observação

Se você já tiver um banco de dados SQL do Azure ou outra instância de SQL Server publicamente acessível que você gostaria de usar, poderá ir para a próxima seção.

Evite habilitar a configuração Permitir que serviços e recursos do Azure acessem este servidor [SQL] para cenários de produção. Os aplicativos reais devem implementar abordagens mais seguras, como restrições de firewall mais fortes ou configurações de rede virtual.

No portal Azure, você pode criar um banco de dados SQL do Azure. Durante a criação:

  • Habilitar os serviços e recursos do Azure para acessar este servidor ( em Rede)
  • Defina o valor para Agrupamento do banco de dados (em Configurações adicionais) como Latin1_General_100_BIN2_UTF8.

Criar um aplicativo Azure Functions e recursos de suporte

  1. Abra uma janela do terminal e entre no Azure:

    az login
    
  2. Crie os seguintes recursos no mesmo grupo de recursos e região que o banco de dados SQL:

    • Uma conta de armazenamento de uso geral, que é usada para armazenar dados importantes do aplicativo, como o próprio código do aplicativo. Os nomes da conta de armazenamento devem conter apenas números de três a 24 caracteres e letras minúsculas.
    • Um plano de aplicativo de funções Premium
    • Um aplicativo de funções
    # Variables
    location=<REGION>
    resourceGroup=<RESOURCE_GROUP_NAME>
    storage=<STORAGE_NAME>
    planName=<PREMIUM_PLAN_NAME>
    functionApp=<APP_NAME>
    skuStorage="Standard_LRS"
    skuPlan="EP1"
    functionsVersion="4"
    
    # Create an Azure storage account
    echo "Creating $storage"
    az storage account create --name $storage --location "$location" --resource-group $resourceGroup --sku $skuStorage --allow-blob-public-access false
    
    # Create a premium plan
    echo "Creating $premiumPlan"
    az functionapp plan create --name $planName --resource-group $resourceGroup --location "$location" --sku $skuPlan
    
    # Create a function app hosted in the premium plan
    echo "Creating $functionApp"
    az functionapp create --name $functionApp --storage-account $storage --plan $planName --resource-group $resourceGroup --functions-version $functionsVersion
    

Criar uma identidade gerenciada do Azure

As identidades gerenciadas tornam seu aplicativo mais seguro eliminando segredos do aplicativo, como credenciais nas cadeias de conexão. Você pode escolher entre a identidade gerenciada atribuída pelo sistema e atribuída pelo usuário. Este início rápido demonstra a configuração da identidade gerenciada atribuída pelo usuário, que é a opção recomendada, pois ela não está vinculada ao ciclo de vida do aplicativo.

Os comandos a seguir criam o recurso de identidade e o atribuem ao aplicativo:

# Variables
subscription=<SUBSCRIPTION_ID>
identity=<IDENTITY_NAME>

# Create a managed identity resource
echo "Creating $identity"
az identity create -g $resourceGroup -n $identity --location "$location"

# Construct the identity resource ID 
resourceId="/subscriptions/$subscription/resourceGroups/$resourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/$identity"

# Assign the identity to the Azure Functions app
echo "Assigning $identity to app"
az functionapp identity assign -g $resourceGroup -n $functionApp --identities "$resourceId"

# Get the identity's ClientId and PrincipalId (also called ObjectId) for a later step. 
clientId=$(az identity show --name $identity --resource-group $resourceGroup --query 'clientId' --output tsv)

principalId=$(az identity show --name $identity --resource-group $resourceGroup --query 'principalId' --output tsv)

Conceder acesso a Armazenamento do Azure e Banco de Dados SQL do Azure

Armazenamento do Azure

Atribua a função de Proprietário de Dados do Blob de Armazenamento à identidade para ter acesso à conta de armazenamento.

# Set the scope of the access
scope="/subscriptions/$subscription/resourceGroups/$resourceGroup/providers/Microsoft.Storage/storageAccounts/$storage"

# Assign the role
echo "Assign Storage Blob Data Owner role to identity"
az role assignment create --assignee "$clientId" --role "Storage Blob Data Owner" --scope "$scope"

Banco de Dados SQL do Azure

A identidade gerenciada precisa de duas concessões: db_owner no banco de dados do aplicativo (para criar e gerenciar esquemas de hub de tarefas) e dbmanager no banco de dados (para permitir operações no master nível do banco de dados durante a inicialização).

Observação

A autenticação no banco de dados SQL do Azure usando a identidade gerenciada não é suportada quando se hospeda um aplicativo Durable Functions no plano de Consumo Flex. Se o aplicativo estiver hospedado no plano de Consumo Flex, vá para a seção definir configurações do aplicativo .

  1. Comece definindo sua identidade de desenvolvedor como administrador do banco de dados.

    O destinatário é sua identidade, portanto, altere para seu email:

    assignee=$(az ad user show --id "someone@example.com" --query "id" --output tsv)
    

    Defina o destinatário como administrador do banco de dados SQL do Azure.

    az sql server ad-admin create --resource-group $resourceGroup --server-name <SQL_SERVER_NAME> --display-name ADMIN --object-id "$assignee"
    
  2. Conecte-se ao banco de dados SQL criado anteriormente usando ferramentas como SQL Management Server Studio ou Visual Studio Code. Ou você pode executar o seguinte comando SQLCMD para se conectar:

    sqlcmd -S <SQL_SERVER_NAME>.database.windows.net -d <DATABASE_NAME> -U <someone@example.com> -P "ACCOUNT_PASSWORD" -G -l 30
    

    Conceda à sua identidade acesso db_owner executando a seguinte consulta no banco de dados. O IDENTITY_OBJECT_ID é o PrincipalId da etapa de criação de identidade.

    CREATE USER "<IDENTITY_NAME>" FROM EXTERNAL PROVIDER With OBJECT_ID='<IDENTITY_OBJECT_ID>'
    ALTER ROLE db_owner ADD MEMBER "<IDENTITY_NAME>";
    GO
    
  3. Conecte-se ao banco de dados master e conceda à sua identidade acesso dbmanager:

    CREATE USER "<IDENTITY_NAME>" FROM EXTERNAL PROVIDER With OBJECT_ID='<IDENTITY_OBJECT_ID>'
    ALTER ROLE dbmanager ADD MEMBER "<IDENTITY_NAME>";
    GO
    

Definir configurações de aplicativo necessárias

Você precisa adicionar as seguintes configurações de aplicativo ao seu aplicativo:

  • AzureWebJobsStorage__accountName: nome da conta Armazenamento do Azure
  • AzureWebJobsStorage__clientId: ClientId da identidade gerenciada
  • AzureWebJobsStorage__credential: tipo de credencial, que é managedidentity
  • SQLDB_Connection: cadeia de conexão do banco de dados SQL

Se você estiver usando a identidade gerenciada atribuída pelo usuário para autenticar no banco de dados SQL, a cadeia de conexão deverá ser semelhante à seguinte:

dbserver=<SQL_SERVER_NAME>
sqlDB=<SQL_DB_NAME>
clientId=<IDENTITY_CLIENT_ID>

sqlconnstr="Server=tcp:$dbserver.database.windows.net,1433;Initial Catalog=$sqlDB;Persist Security Info=False;User ID=$clientId;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Authentication='Active Directory Managed Identity';"

Para aplicativos de Consumo Flexível, use uma cadeia de conexão para se autenticar por enquanto. Você pode encontrá-lo acessando o recurso do banco de dados SQL no portal do Azure, navegando até a guia Configurações e clicando em Cadeias de conexão:

Captura de tela da página de strings de conexão do banco de dados SQL do Azure no Azure portal.

O cadeia de conexão deve ter esse formato:

dbserver=<SQL_SERVER_NAME>
sqlDB=<SQL_DB_NAME>
username=<DB_USER_LOGIN>
password=<DB_USER_PASSWORD>

sqlconnstr="Server=tcp:$dbserver.database.windows.net,1433;Initial Catalog=$sqlDB;Persist Security Info=False;User ID=$username;Password=$password;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"

Execute o seguinte comando para definir as configurações:

az functionapp config appsettings set --name $functionApp --resource-group $resourceGroup --settings AzureWebJobsStorage__accountName="$storage" AzureWebJobsStorage__clientId="$clientId" AzureWebJobsStorage__credential="managedidentity" SQLDB_Connection=$sqlconnstr

Exclua a configuração existente AzureWebJobsStorage :

az functionapp config appsettings delete --name $functionApp --resource-group $resourceGroup --setting-names "AzureWebJobsStorage"

Implantar o projeto local no Azure e testar

Por fim, na pasta do projeto raiz, implante seu aplicativo no Azure executando:

func azure functionapp publish $functionApp

Após a conclusão da implantação, execute o seguinte para obter a URL do gatilho HTTP:

az functionapp function list --resource-group $resourceGroup --name $functionApp  --query '[].{Function:name, URL:invokeUrlTemplate}' --output json

Teste exatamente como você fez durante o desenvolvimento local com uma ferramenta de teste HTTP.

Você também pode validar se o back-end do MSSQL está configurado corretamente consultando o banco de dados para dados do hub de tarefas.

Por exemplo, você pode consultar suas instâncias de orquestração no painel de visão geral do seu banco de dados SQL. Selecione Editor de Consultas, autentique e execute a seguinte consulta:

SELECT TOP 5 InstanceID, RuntimeStatus, CreatedTime, CompletedTime FROM dt.Instances

Após executar um orquestrador simples, você deverá ver pelo menos um resultado, conforme mostrado nesse exemplo:

Captura de tela mostrando os resultados do Editor de Consultas do SQL do Azure para a consulta SQL.

Próximas Etapas