Conectar o Azure Functions ao Armazenamento do Azure usando ferramentas de linha de comando

Neste artigo, você integra uma fila de Armazenamento do Azure com a função e a conta de armazenamento criadas no artigo de início rápido anterior. Você obtém essa integração usando uma associação de saída que grava dados de uma solicitação HTTP em uma mensagem na fila. A conclusão deste artigo não implica custos adicionais além dos poucos centavos de dólar do início rápido anterior. Para saber mais sobre associações, consulte Conceitos de acionadores e associações do Azure Functions.

Configure seu ambiente local

Antes de começar, você deve concluir o artigo Guia de início rápido: criar um projeto do Azure Functions a partir da linha de comando. Se você já limpou recursos no final desse artigo, siga as etapas novamente para recriar o aplicativo de função e os recursos relacionados no Azure.

Antes de começar, você deve concluir o artigo Guia de início rápido: criar um projeto do Azure Functions a partir da linha de comando. Se você já limpou recursos no final desse artigo, siga as etapas novamente para recriar o aplicativo de função e os recursos relacionados no Azure.

Antes de começar, você deve concluir o artigo Guia de início rápido: criar um projeto do Azure Functions a partir da linha de comando. Se você já limpou recursos no final desse artigo, siga as etapas novamente para recriar o aplicativo de função e os recursos relacionados no Azure.

Antes de começar, você deve concluir o artigo Guia de início rápido: criar um projeto do Azure Functions a partir da linha de comando. Se você já limpou recursos no final desse artigo, siga as etapas novamente para recriar o aplicativo de função e os recursos relacionados no Azure.

Antes de começar, você deve concluir o artigo Guia de início rápido: criar um projeto do Azure Functions a partir da linha de comando. Se você já limpou recursos no final desse artigo, siga as etapas novamente para recriar o aplicativo de função e os recursos relacionados no Azure.

Antes de começar, você deve concluir o artigo Guia de início rápido: criar um projeto do Azure Functions a partir da linha de comando. Se você já limpou recursos no final desse artigo, siga as etapas novamente para recriar o aplicativo de função e os recursos relacionados no Azure.

Recuperar a cadeia de conexão do Armazenamento do Azure

Anteriormente, você criou uma conta de Armazenamento do Azure para uso do aplicativo de função. A cadeia de conexão para essa conta é armazenada com segurança nas configurações do aplicativo no Azure. Ao baixar a configuração no arquivo local.settings.json , você pode usar a conexão para gravar em uma fila de armazenamento na mesma conta ao executar a função localmente.

  1. Na raiz do projeto, execute o seguinte comando, substitua <APP_NAME> pelo nome do seu aplicativo de função da etapa anterior. Este comando substitui quaisquer valores existentes no arquivo.

    func azure functionapp fetch-app-settings <APP_NAME>
    
  2. Abra local.settings.json arquivo e localize o valor chamado AzureWebJobsStorage, que é a cadeia de conexão da conta de armazenamento. Use o nome AzureWebJobsStorage e a cadeia de conexão em outras seções deste artigo.

Importante

Como o arquivo local.settings.json contém segredos baixados do Azure, sempre exclua esse arquivo do controle do código-fonte . O arquivo .gitignore criado com um projeto de funções locais exclui o arquivo por padrão.

Registar as extensões de enlace

Exceto para gatilhos HTTP e timer, as ligações são implementadas como pacotes de extensão. Execute o seguinte comando dotnet add package na janela Terminal para adicionar o pacote de extensão de armazenamento ao seu projeto.

dotnet add package Microsoft.Azure.Functions.Worker.Extensions.Storage.Queues --prerelease

Agora, você pode adicionar a vinculação de saída de armazenamento ao seu projeto.

Adicionar uma definição de vinculação de saída à função

Embora uma função possa ter apenas um gatilho, ela pode ter várias ligações de entrada e saída, o que permite que você se conecte a outros serviços e recursos do Azure sem escrever código de integração personalizado.

Ao usar o modelo de programação Node.js v4, os atributos de ligação são definidos diretamente no arquivo ./src/functions/HttpExample.js . A partir do início rápido anterior, seu arquivo já contém uma ligação HTTP definida pelo app.http método.

const { app } = require('@azure/functions');

app.http('httpTrigger', {
  methods: ['GET', 'POST'],
  authLevel: 'anonymous',
  handler: async (request, context) => {
    try {
      context.log(`Http function processed request for url "${request.url}"`);

      const name = request.query.get('name') || (await request.text());
      context.log(`Name: ${name}`);

      if (!name) {
        return { status: 404, body: 'Not Found' };
      }

      return { body: `Hello, ${name}!` };
    } catch (error) {
      context.log(`Error: ${error}`);
      return { status: 500, body: 'Internal Server Error' };
    }
  },
});

Ao usar o modelo de programação Node.js v4, os atributos de ligação são definidos diretamente no arquivo ./src/functions/HttpExample.js . A partir do início rápido anterior, seu arquivo já contém uma ligação HTTP definida pelo app.http método.

import {
  app,
  HttpRequest,
  HttpResponseInit,
  InvocationContext,
} from '@azure/functions';

export async function httpTrigger1(
  request: HttpRequest,
  context: InvocationContext,
): Promise<HttpResponseInit> {
  context.log(`Http function processed request for url "${request.url}"`);

  const name = request.query.get('name') || (await request.text()) || 'world';

  return { body: `Hello, ${name}!` };
}

app.http('httpTrigger1', {
  methods: ['GET', 'POST'],
  authLevel: 'anonymous',
  handler: httpTrigger1,
});

Você declara essas associações no arquivo function.json na pasta de funções. A partir do início rápido anterior, seu arquivo de function.json na pasta HttpExample contém duas associações na bindings coleção:

Ao usar o modelo de programação Python v2, os atributos de ligação são definidos diretamente no arquivo function_app.py como decoradores. A partir do início rápido anterior, seu arquivo de function_app.py já contém uma ligação baseada em decorador:

import azure.functions as func
import logging

app = func.FunctionApp()

@app.function_name(name="HttpTrigger1")
@app.route(route="hello", auth_level=func.AuthLevel.ANONYMOUS)

O route decorador adiciona a ligação HttpTrigger e HttpOutput à função, o que permite que sua função seja acionada quando as solicitações http atingem a rota especificada.

Para gravar em uma fila de Armazenamento do Azure a partir dessa função, adicione o decorador queue_output ao seu código de função:

@app.queue_output(arg_name="msg", queue_name="outqueue", connection="AzureWebJobsStorage")

No decorador, arg_name identifica o parâmetro de vinculação referenciado em seu código, queue_name é o nome da fila na qual a associação grava e connection é o nome de uma configuração de aplicativo que contém a cadeia de conexão para a conta de armazenamento. Em inícios rápidos, você usa a mesma conta de armazenamento que o aplicativo de função, que está na AzureWebJobsStorage configuração (de local.settings.json arquivo). Quando o queue_name não existe, a ligação cria-o na primeira utilização.

"bindings": [
  {
    "authLevel": "function",
    "type": "httpTrigger",
    "direction": "in",
    "name": "Request",
    "methods": [
      "get",
      "post"
    ]
  },
  {
    "type": "http",
    "direction": "out",
    "name": "Response"
  }
]

Para gravar em uma fila de Armazenamento do Azure:

  • Adicionar uma extraOutputs propriedade à configuração de vinculação

    {
        methods: ['GET', 'POST'],
        extraOutputs: [sendToQueue], // add output binding to HTTP trigger
        authLevel: 'anonymous',
        handler: () => {}
    }
    
  • Adicionar uma output.storageQueue função acima da app.http chamada

    const sendToQueue: StorageQueueOutput = output.storageQueue({
      queueName: 'outqueue',
      connection: 'AzureWebJobsStorage',
    });
    

A segunda ligação na coleção é denominada res. Essa http associação é uma ligação de saída (out) que é usada para gravar a resposta HTTP.

Para gravar em uma fila de Armazenamento do Azure a partir dessa função, adicione uma out associação do tipo queue com o nome msg, conforme mostrado no código abaixo:

    {
      "authLevel": "function",
      "type": "httpTrigger",
      "direction": "in",
      "name": "Request",
      "methods": [
        "get",
        "post"
      ]
    },
    {
      "type": "http",
      "direction": "out",
      "name": "Response"
    },
    {
      "type": "queue",
      "direction": "out",
      "name": "msg",
      "queueName": "outqueue",
      "connection": "AzureWebJobsStorage"
    }
  ]
}

Para um queue tipo, você deve especificar o nome da fila e queueName fornecer o nome da conexão de Armazenamento do Azure (de local.settings.json arquivo) em connection.

Em um projeto C#, as ligações são definidas como atributos de ligação no método de função. As definições específicas dependem se seu aplicativo é executado em processo (biblioteca de classes C#) ou em um processo de trabalho isolado.

Abra o arquivo de projeto HttpExample.cs e adicione a seguinte MultiResponse classe:

public class MultiResponse
{
    [QueueOutput("outqueue",Connection = "AzureWebJobsStorage")]
    public string[] Messages { get; set; }
    public HttpResponseData HttpResponse { get; set; }
}

A MultiResponse classe permite que você escreva em uma fila de armazenamento nomeada outqueue e uma mensagem de sucesso HTTP. Várias mensagens podem ser enviadas para a fila porque o QueueOutput atributo é aplicado a uma matriz de cadeia de caracteres.

A Connection propriedade define a cadeia de conexão para a conta de armazenamento. Nesse caso, você pode omitir Connection porque já está usando a conta de armazenamento padrão.

Em um projeto Java, as ligações são definidas como anotações de ligação no método function. O arquivo function.json é gerado automaticamente com base nessas anotações.

Navegue até o local do código da função em src/main/java, abra o arquivo de projeto Function.java e adicione o seguinte parâmetro à definição do run método:

@QueueOutput(name = "msg", queueName = "outqueue", connection = "AzureWebJobsStorage") OutputBinding<String> msg

O msg parâmetro é um OutputBinding<T> tipo, que representa uma coleção de cadeias de caracteres. Essas cadeias de caracteres são gravadas como mensagens para uma ligação de saída quando a função é concluída. Nesse caso, a saída é uma fila de armazenamento chamada outqueue. A cadeia de conexão para a conta de armazenamento é definida pelo connection método. Você passa a configuração do aplicativo que contém a cadeia de conexão da conta de armazenamento, em vez de passar a cadeia de conexão em si.

A run definição do método agora deve se parecer com o exemplo a seguir:

@FunctionName("HttpTrigger-Java")
public HttpResponseMessage run(
        @HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.FUNCTION)  
        HttpRequestMessage<Optional<String>> request, 
        @QueueOutput(name = "msg", queueName = "outqueue", connection = "AzureWebJobsStorage") 
        OutputBinding<String> msg, final ExecutionContext context) {
    ...
}

Para obter mais informações sobre os detalhes das associações, consulte Conceitos de gatilhos e ligações do Azure Functions e configuração de saída de fila.

Adicionar código para usar a associação de saída

Com a vinculação de fila definida, agora você pode atualizar sua função para receber o msg parâmetro de saída e gravar mensagens na fila.

Atualize HttpExample\function_app.py para corresponder ao código a seguir, adicione o msg parâmetro à definição da função e msg.set(name) sob a if name: instrução:

import azure.functions as func
import logging

app = func.FunctionApp(http_auth_level=func.AuthLevel.ANONYMOUS)

@app.route(route="HttpExample")
@app.queue_output(arg_name="msg", queue_name="outqueue", connection="AzureWebJobsStorage")
def HttpExample(req: func.HttpRequest, msg: func.Out [func.QueueMessage]) -> func.HttpResponse:
    logging.info('Python HTTP trigger function processed a request.')

    name = req.params.get('name')
    if not name:
        try:
            req_body = req.get_json()
        except ValueError:
            pass
        else:
            name = req_body.get('name')

    if name:
        msg.set(name)
        return func.HttpResponse(f"Hello, {name}. This HTTP triggered function executed successfully.")
    else:
        return func.HttpResponse(
             "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response.",
             status_code=200
        )

O msg parâmetro é uma instância do azure.functions.Out class. O set método grava uma mensagem de cadeia de caracteres na fila. Nesse caso, é o name passado para a função na cadeia de caracteres de consulta de URL.

Adicione código que usa o objeto de vinculação de saída para context.extraOutputs criar uma mensagem de fila. Adicione este código antes da instrução return.

context.extraOutputs.set(sendToQueue, [msg]);

Neste ponto, sua função pode ter a seguinte aparência:

const { app, output } = require('@azure/functions');

const sendToQueue = output.storageQueue({
  queueName: 'outqueue',
  connection: 'AzureWebJobsStorage',
});

app.http('HttpExample', {
  methods: ['GET', 'POST'],
  authLevel: 'anonymous',
  extraOutputs: [sendToQueue],
  handler: async (request, context) => {
    try {
      context.log(`Http function processed request for url "${request.url}"`);

      const name = request.query.get('name') || (await request.text());
      context.log(`Name: ${name}`);

      if (name) {
        const msg = `Name passed to the function ${name}`;
        context.extraOutputs.set(sendToQueue, [msg]);
        return { body: msg };
      } else {
        context.log('Missing required data');
        return { status: 404, body: 'Missing required data' };
      }
    } catch (error) {
      context.log(`Error: ${error}`);
      return { status: 500, body: 'Internal Server Error' };
    }
  },
});

Adicione código que usa o objeto de vinculação de saída para context.extraOutputs criar uma mensagem de fila. Adicione este código antes da instrução return.

context.extraOutputs.set(sendToQueue, [msg]);

Neste ponto, sua função pode ter a seguinte aparência:

import {
  app,
  output,
  HttpRequest,
  HttpResponseInit,
  InvocationContext,
  StorageQueueOutput,
} from '@azure/functions';

const sendToQueue: StorageQueueOutput = output.storageQueue({
  queueName: 'outqueue',
  connection: 'AzureWebJobsStorage',
});

export async function HttpExample(
  request: HttpRequest,
  context: InvocationContext,
): Promise<HttpResponseInit> {
  try {
    context.log(`Http function processed request for url "${request.url}"`);

    const name = request.query.get('name') || (await request.text());
    context.log(`Name: ${name}`);

    if (name) {
      const msg = `Name passed to the function ${name}`;
      context.extraOutputs.set(sendToQueue, [msg]);
      return { body: msg };
    } else {
      context.log('Missing required data');
      return { status: 404, body: 'Missing required data' };
    }
  } catch (error) {
    context.log(`Error: ${error}`);
    return { status: 500, body: 'Internal Server Error' };
  }
}

app.http('HttpExample', {
  methods: ['GET', 'POST'],
  authLevel: 'anonymous',
  handler: HttpExample,
});

Adicione código que usa o Push-OutputBinding cmdlet para gravar texto na fila usando a msg associação de saída. Adicione este código antes de definir o status OK na if instrução.

$outputMsg = $name
Push-OutputBinding -name msg -Value $outputMsg

Neste ponto, sua função deve ter a seguinte aparência:

using namespace System.Net

# Input bindings are passed in via param block.
param($Request, $TriggerMetadata)

# Write to the Azure Functions log stream.
Write-Host "PowerShell HTTP trigger function processed a request."

# Interact with query parameters or the body of the request.
$name = $Request.Query.Name
if (-not $name) {
    $name = $Request.Body.Name
}

if ($name) {
    # Write the $name value to the queue, 
    # which is the name passed to the function.
    $outputMsg = $name
    Push-OutputBinding -name msg -Value $outputMsg

    $status = [HttpStatusCode]::OK
    $body = "Hello $name"
}
else {
    $status = [HttpStatusCode]::BadRequest
    $body = "Please pass a name on the query string or in the request body."
}

# Associate values to output bindings by calling 'Push-OutputBinding'.
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
    StatusCode = $status
    Body = $body
})

Substitua a classe existente HttpExample pelo seguinte código:

    [Function("HttpExample")]
    public static MultiResponse Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req,
        FunctionContext executionContext)
    {
        var logger = executionContext.GetLogger("HttpExample");
        logger.LogInformation("C# HTTP trigger function processed a request.");

        var message = "Welcome to Azure Functions!";

        var response = req.CreateResponse(HttpStatusCode.OK);
        response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
        response.WriteString(message);

        // Return a response to both HTTP trigger and storage output binding.
        return new MultiResponse()
        {
            // Write a single message.
            Messages = new string[] { message },
            HttpResponse = response
        };
    }
}

Agora, você pode usar o novo msg parâmetro para gravar na ligação de saída do seu código de função. Adicione a seguinte linha de código antes da resposta de sucesso para adicionar o valor de à msg ligação de name saída.

msg.setValue(name);

Quando você usa uma associação de saída, não precisa usar o código do SDK do Armazenamento do Azure para autenticação, obtenção de uma referência de fila ou gravação de dados. O tempo de execução do Functions e a vinculação de saída da fila fazem essas tarefas por você.

Seu run método agora deve se parecer com o exemplo a seguir:

public HttpResponseMessage run(
        @HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) 
        HttpRequestMessage<Optional<String>> request, 
        @QueueOutput(name = "msg", queueName = "outqueue", 
        connection = "AzureWebJobsStorage") OutputBinding<String> msg, 
        final ExecutionContext context) {
    context.getLogger().info("Java HTTP trigger processed a request.");

    // Parse query parameter
    String query = request.getQueryParameters().get("name");
    String name = request.getBody().orElse(query);

    if (name == null) {
        return request.createResponseBuilder(HttpStatus.BAD_REQUEST)
        .body("Please pass a name on the query string or in the request body").build();
    } else {
        // Write the name to the message queue. 
        msg.setValue(name);

        return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + name).build();
    }
}

Atualizar os testes

Como o arquétipo também cria um conjunto de testes, você precisa atualizar esses testes para manipular o novo msg parâmetro na assinatura do run método.

Navegue até o local do seu código de teste em src/test/java, abra o arquivo de projeto Function.java e substitua a linha de código em //Invoke pelo seguinte código:

@SuppressWarnings("unchecked")
final OutputBinding<String> msg = (OutputBinding<String>)mock(OutputBinding.class);
final HttpResponseMessage ret = new Function().run(req, msg, context);

Observe que você não precisa escrever nenhum código para autenticação, obter uma referência de fila ou gravar dados. Todas essas tarefas de integração são convenientemente tratadas no tempo de execução do Azure Functions e na vinculação de saída da fila.

Executar a função localmente

  1. Execute sua função iniciando o host de tempo de execução local do Azure Functions a partir da pasta LocalFunctionProj .

    func start
    

    No final da saída, as seguintes linhas devem aparecer:

    Captura de tela da saída da janela do terminal ao executar a função localmente.

    Nota

    Se HttpExample não aparecer como mostrado acima, você provavelmente iniciou o host de fora da pasta raiz do projeto. Nesse caso, use Ctrl+C para parar o host, vá para a pasta raiz do projeto e execute o comando anterior novamente.

  2. Copie o URL da sua função HTTP desta saída para um navegador e anexe a cadeia de caracteres ?name=<YOUR_NAME>de consulta, tornando o URL completo como http://localhost:7071/api/HttpExample?name=Functions. O navegador deve exibir uma mensagem de resposta que ecoe o valor da cadeia de caracteres de consulta. O terminal no qual você iniciou seu projeto também mostra a saída de log à medida que você faz solicitações.

  3. Quando terminar, pressione Ctrl + C e digite y para parar o host de funções.

Gorjeta

Durante a inicialização, o host baixa e instala a extensão de vinculação de armazenamento e outras extensões de vinculação da Microsoft. Essa instalação acontece porque as extensões de vinculação são habilitadas por padrão no arquivo host.json com as seguintes propriedades:

{
    "version": "2.0",
    "extensionBundle": {
        "id": "Microsoft.Azure.Functions.ExtensionBundle",
        "version": "[1.*, 2.0.0)"
    }
}

Se você encontrar algum erro relacionado a extensões de vinculação, verifique se as propriedades acima estão presentes no host.json.

Exibir a mensagem na fila de Armazenamento do Azure

Você pode exibir a fila no portal do Azure ou no Gerenciador de Armazenamento do Microsoft Azure. Você também pode exibir a fila na CLI do Azure, conforme descrito nas seguintes etapas:

  1. Abra o arquivo local.setting.json do projeto de função e copie o valor da cadeia de conexão. Em um terminal ou janela de comando, execute o seguinte comando para criar uma variável de ambiente chamada AZURE_STORAGE_CONNECTION_STRING, e cole sua cadeia de conexão específica no lugar de <MY_CONNECTION_STRING>. (Essa variável de ambiente significa que você não precisa fornecer a cadeia de conexão para cada comando subsequente usando o --connection-string argumento.)

    export AZURE_STORAGE_CONNECTION_STRING="<MY_CONNECTION_STRING>"
    
  2. (Opcional) Use o az storage queue list comando para exibir as filas de armazenamento em sua conta. A saída desse comando deve incluir uma fila chamada outqueue, que foi criada quando a função escreveu sua primeira mensagem para essa fila.

    az storage queue list --output tsv
    
  3. Use o az storage message get comando para ler a mensagem dessa fila, que deve ser o valor fornecido ao testar a função anteriormente. O comando lê e remove a primeira mensagem da fila.

    echo `echo $(az storage message get --queue-name outqueue -o tsv --query '[].{Message:content}') | base64 --decode`
    

    Como o corpo da mensagem é armazenado codificado em base64, a mensagem deve ser decodificada antes de ser exibida. Depois de executar az storage message geto , a mensagem é removida da fila. Se houver apenas uma mensagem no , você não recuperará uma mensagem quando executar esse comando uma segunda vez e, em outqueuevez disso, receberá um erro.

Reimplantar o projeto no Azure

Agora que você verificou localmente que a função escreveu uma mensagem na fila de Armazenamento do Azure, você pode reimplantar seu projeto para atualizar o ponto de extremidade em execução no Azure.

Na pasta LocalFunctionsProj, use o func azure functionapp publish comando para reimplantar o projeto, substituindo<APP_NAME> pelo nome do seu aplicativo.

func azure functionapp publish <APP_NAME>

Na pasta do projeto local, use o seguinte comando Maven para publicar novamente seu projeto:

mvn azure-functions:deploy

Verificar no Azure

  1. Como no início rápido anterior, use um navegador ou CURL para testar a função reimplantada.

    Copie o URL Invoke completo mostrado na saída do comando publish em uma barra de endereço do navegador, anexando o parâmetro &name=Functionsquery . O navegador deve exibir a mesma saída de quando você executou a função localmente.

  2. Examine a fila de armazenamento novamente, conforme descrito na seção anterior, para verificar se ela contém a nova mensagem gravada na fila.

Clean up resources (Limpar recursos)

Depois de terminar, use o seguinte comando para excluir o grupo de recursos e todos os recursos contidos para evitar incorrer em custos adicionais.

az group delete --name AzureFunctionsQuickstart-rg

Próximos passos

Você atualizou sua função acionada por HTTP para gravar dados em uma fila de armazenamento. Agora você pode saber mais sobre o desenvolvimento de funções a partir da linha de comando usando as Ferramentas Principais e a CLI do Azure: