Por que eu devo ler este artigo: Esse artigo é útil para quem deseja adentrar no mundo da computação serverless. Conheça uma das mais novas e promissoras áreas da computação que visa prover a execução de rotinas de software rápidas e baratas na nuvem, alocando o mínimo de recursos possíveis se, e somente se, requisições forem solicitadas ao servidor. Dessa forma, o leitor poderá entender como conectar o já conhecido mundo do .NET, C# e programação para Azure com as novas Azure Functions: os “pedaços” de código que executam independentemente no servidor.

Muito tem-se falado sobre o mundo serverless, à luz dos limites rompidos por tecnologias como AWS Lambda e Google Cloud Functions, temos agora a possibilidade de ser mais modular, ocupar menos recursos físicos (hardware, processamento, memória, etc.) e, consequentemente, gastar muito menos quando se trata de criar softwares.


Guia do artigo:


Computação serverless, em termos rápidos, é um modelo de execução de código onde a lógica do lado servidor se dá de forma stateless, isto é, sem estado, a partir de gatilhos (triggers), e via containers que são totalmente gerenciados por um terceiro. Muitas vezes sua definição é associada à Functions as a Service (FaaS), um termo mais popular para quando queremos focar mais na implementação em vez dos detalhes de como a aplicação irá ser deployada e/ou executada no servidor.

Em diferentes linguagens de programação, podemos encontrar os termos "função", "procedimento" e "método" referindo-se a diferentes tipos de rotinas executando uma tarefa. Neste contexto, o termo função não é específico da linguagem de programação, mas conceitual: na programação, uma função é uma seção nomeada de um programa que executa uma tarefa específica.

Ironicamente, a computação serverless não é, de fato, executada sem servidores. Em vez disso, ela envolve a terceirização do provisionamento e gerenciamento de servidores para um terceiro.

Quase todas as tecnologias de computação sem servidor existentes são disponibilizadas por grandes fornecedores de nuvem pública. A grande escala dos fornecedores de nuvens públicas atuais permite duas coisas para tornar o servidor ainda mais interessante:

  • Entendem os benefícios de custo na economia de escala: para qualquer equipe de desenvolvimento específica, ou mesmo organização, seria difícil alcançar a escala de gerenciamento de contêineres para aplicações de computação gerenciados separadamente. Na escala de vendedores de nuvem pública, o cálculo sem servidor torna-se barato porque a alocação de potência de computação é equilibrada em milhares de servidores e bilhões de execuções, com cada aplicação cliente atingindo limites de pico em momentos diferentes. A natureza dos centros de dados de software também permite uma alocação de servidores mais eficiente;
  • Minimizamos efeitos adversos do bloqueio de fornecedores: o mundo moderno de TI está rapidamente chegando ao consenso de que os benefícios da nuvem pública superam as desvantagens de qualquer bloqueio de fornecedores que vem com ele. Com muitos serviços de TI que se deslocam para a nuvem pública, torna-se mais fácil e mais benéfico aproveitar um provedor de nuvem para hospedar aplicativos serverless .

Para ilustrar onde a computação serverless entraria em sua aplicação, vamos dar uma olhada em uma arquitetura clássica de três camadas. Nesta abordagem comumente utilizada, o aplicativo é dividido nas seguintes camadas:

  • Camada de apresentação:manipula a interface do usuário e, normalmente, opera como umcliente cleanem uma web ou dispositivo móvel;
  • Camada de lógica:também conhecida como camada da aplicação, lida com a lógica do processo funcional e as regras de negócio da aplicação. Este nível pode atender a um ou mais clientes da camada de apresentação, além de conseguir escalar independentemente das demais;
  • Camada de dados: a camada de dados persiste os dados do aplicativo em bancos de dados ou compartilhamentos de arquivos e lida com a camada de acesso aos mesmos.

A partir do momento que introduzimos o conceito de computação serverless, todas ou partes da sua aplicação na concepção que a conhece hoje, podem ser substituídas pelos containers serverless, ou FaaS. Dependendo da aplicação, funções podem lidar com toda a lógica de negócio, ou trabalhar em conjunto com outros tipos de serviços para constituir o todo desta camada. Por exemplo, considere uma aplicação que recebe dados de cartão de crédito de um usuário. Convencionalmente, teríamos várias camadas de serviços deployadas no servidor, que proveriam uma série de validações no momento em que uma transação chegasse à nossa aplicação. Cada validação, no universo das serverless, constitui uma função que, por sua vez, se comunica com outras funções ou serviços externos (das Mastercard, por exemplo), e assim por diante.

Apesar disso, nem todas as facetas da computação tradicional podem ser substituídas. Por exemplo, algumas das características implícitas da computação serverless impossibilitam operações tradicionais, como o fato de que ela é, por default, assíncrona, isto é, baseada em eventos que são trigados (triggers) a partir do acontecimento de determinadas ações assíncronas na aplicação. Em vista disso, é importante que a sua programação leve em consideração o uso de funções não-blocking, que sejam passíveis de espera.

Vejamos mais alguns estados importantes do serverless nos tópicos a seguir.

Stateless

Programação serverless é, por padrão, stateless, isto é, não pode guardar estado. O conceito já é bem conhecido em aplicações enterprise que fazem uso extensivo de objetos beans para execução de tarefas de negócio simples, independentes e, como o próprio nome sugere, sem estado. Ele vai além, se estendendo a restrições também para execuções paralelas e sequenciais, exigindo um certo jogo de cintura do programador para entender que seu estado, agora, deve ser salvo em um banco de dados, um servidor de arquivos, cache ou quaisquer estruturas que permitam isso de forma integrada, não mais interna à execução da aplicação.

O paradigma stateless facilitou em muito a construção e escalabilidade de aplicações nos últimos anos especialmente por seu deploy rápido e fácil acesso aos recursos. Todavia, nem tudo é perfeito: o maior benefício de ter um estado local é a baixa latência de acesso, e algumas aplicações não conseguem atingir boas performances sem isso. Como um exemplo, consideremos a construção de uma aplicação usada para trade de mercado financeiro, persistindo o estado em um banco de dados ou até mesmo num cache, o que pode se tornar extremamente custoso. Aplicações que requerem um estado local não se encaixarão bem no modelo serverless.

Note-se ainda que alguns provedores de computação serverless te previnem completamente de eventuais acessos à máquina hospedeira. Com o Azure Functions, você tem acesso de leitura/escrita ao disco virtual D: da máquina host, entretanto, é altamente recomendável que você não o use para persistir estado.

Idempotente e defensivo

Para garantir a consistência, as funções de computação serverless devem ser idempotentes. Matematicamente, uma função é idempotente se, sempre que for aplicada duas vezes em qualquer valor, der o mesmo resultado que se fosse aplicada uma vez, ou seja, ƒ(ƒ(x)) ≡ ƒ(x) .

Para dar um exemplo simples de uma função não idempotente, imagine uma função com uma tarefa de cálculo de uma raiz quadrada dado um número de entrada. Se a função for executada uma segunda vez em um valor de entrada que já foi processado, resultará em uma saída incorreta, como temos em √(√(x)) ≠ √(x) . Assim, a única maneira de garantir que a função permaneça idempotente é garantir que a mesma entrada não seja processada duas vezes.

Em um ambiente assíncrono, altamente paralelizado, executado por containers de computação efêmeros, é preciso uma dose extra de trabalho para garantir que os erros de execução não impactem em todos os eventos subsequentes. O que acontece quando uma função falha no meio da codificação de um arquivo de mídia grande? O que acontece se uma função encarregada de processar 100 linhas em um banco de dados falhar antes de terminar? Será que o restante da entrada permanecerá não processado, ou sua parte já processada será processada de novo?

Para garantir a consistência, precisamos armazenar as informações de estado necessárias com nossos dados, permitindo que uma função termine graciosamente se não for necessário mais processamento. Além disso, precisamos implementar um padrão de circuit-breaker para garantir que uma função com falha não tente novamente infinitamente.

O Azure Functions, em particular, possui mecanismos de defesa internos que você pode aproveitar. Por exemplo, para uma função de fila de armazenamento, um processamento de mensagens da fila será reiniciado cinco vezes em caso de falha, após o qual será descartado para uma fila de mensagens DLQ, por exemplo.

Limitações de execução

Em comparação com uma aplicação tradicional, um ambiente FaaS tem duas restrições de execução muito importantes: o tempo que a função pode executar e o tempo necessário para iniciar a primeira execução da função após um período de inatividade.

Em um ambiente FaaS, o tempo de execução de cada função deve ser o mais curto possível. Alguns fornecedores impõem limites rígidos de até alguns minutos que devem ser rigidamente obedecidos. Esses limites determinam um certo estilo de programação, mas podem ser complicados de lidar.

Os Azure Functions são oferecidos em dois planos de hospedagem diferentes: um plano de consumo (Consumption plan) e um plano de serviço de aplicativos (App Service plan). O plano de consumo escala dinamicamente sob demanda, enquanto um plano de serviço de aplicativos sempre possui pelo menos uma instância da VM provisionada. Devido às diferentes abordagens para provisionamento de recursos, esses planos têm diferentes restrições de execução.

No plano de App Service, não há limite no tempo de execução da função. Já no plano Consumption há um limite padrão de cinco minutos, que pode ser aumentado até 10 minutos efetuando uma alteração na configuração da função.

Mesmo no plano do serviço de aplicativos, no entanto, é altamente recomendável manter o tempo de execução da função o mais curto possível. Uma função de longa execução pode ser dividida em funções mais curtas, onde cada uma executa uma tarefa específica.

Latência de inicialização

Em um ambiente FaaS, as funções devem ser mantidas o mais leve possível. Carregar muitas dependências externas explícitas ou implícitas pode aumentar o tempo de carregamento da função e até causar tempos de espera. Assim, as funções devem manter suas dependências externas ao mínimo.

Além disso, na maioria dos ambientes FaaS, as funções enfrentam uma latência de inicialização significativamente aumentada. Após um período de inatividade, uma função não utilizada fica ociosa. A próxima vez que a função for carregada, o cálculo e a memória precisarão ser alocados, as dependências externas precisarão ser carregadas e, no caso de linguagens compiladas como C#, o código precisa ser recompilado. Todos esses fatores podem causar um atraso significativo no tempo de inicialização da função.

Nas funções baseadas no Azure C#, especificamente, o problema de inicialização foi atenuado com o lançamento das funções baseadas na .NET Class Library, uma vez que as funções são pré-compiladas e podem ser carregadas mais rapidamente. Além disso, quando executado no plano App Service, o problema de inicialização é eliminado.

Principais vantagens

As vantagens do FaaS podem ser agrupadas em algumas categorias. Algumas das vantagens existem na maioria dos ambientes PaaS (Platform as a Service), no entanto, elas podem ser melhor notadas em um ambiente FaaS.

Algumas das vantagens são semelhantes às vantagens da popular arquitetura de microsserviços, na qual a aplicação está estruturada como uma coleção de serviços de baixo acoplamento, cada uma das quais lidando com uma tarefa específica.

Escalabilidade

A computação serverless torna muito fácil escalar aplicações, fornecendo mais poder de computação, conforme necessário, e desalocando-o quando a demanda for baixa. Isso permite que os desenvolvedores evitem o risco de ter a aplicação falhando para seus usuários durante uma demanda de pico, e evitando ao mesmo tempo o custo de alocar infraestrutura de reserva maciça.

Isso torna a computação serverless particularmente útil para aplicativos com tráfego inconsistente. Vejamos os seguintes exemplos:

  • Uma aplicação usada durante eventos esportivos: neste caso, sua aplicação provavelmente apresentará cargas de tráfego altamente variáveis, com uma diferença significativa entre alto e baixo tráfegos. O serverless pode ajudar a mitigar a complexidade e o custo de fornecer um serviço adequado;
  • Uma aplicação de varejo: é comum que as aplicações de varejo experimentem cargas extremamente elevadas durante as estações de férias ou durante campanhas de marketing. Embora essas cargas sejam previsíveis, elas geralmente diferem tão significativamente da carga diária, que manter a infraestrutura de reserva necessária pode se tornar muito dispendioso. Com o serverless podemos eliminar a necessidade dessa infraestrutura;
  • Uma aplicação de atualização de mídia social periódica: imagine uma aplicação que publica uma atualização de um feed do Twitter uma vez por hora. Esta aplicação requer muito pouco poder de computação. No mundo da TI tradicional, tal aplicação normalmente seria executada em dois servidores para garantir a resiliência, que é um extremo desperdício do ponto de vista do poder de computação. A implantação de múltiplos aplicativos para o mesmo servidor pode muitas vezes tornar-se problemática por razões operacionais/organizacionais e, na maioria das organizações, o poder de computação local está fortemente subutilizado (no local, as equipes tendem a sobrecarregar significativamente o hardware porque é bastante difícil adicionar mais poder de computação no futuro). A computação serverless se encaixa muito bem para resolver esse problema.

É importante notar que a vantagem de escalabilidade também existe nos serviços PaaS, no entanto, com a computação serverless, a escala geralmente é completamente dinâmica e tratada pelo fornecedor. Isso significa que, enquanto estiver em um serviço PaaS típico, você precisará definir métricas (como alta utilização de CPU ou memória) e, até certo ponto, definir o procedimento de dimensionamento (como uma série de nós adicionais para provisionar ou se a aplicação precisa diminuir a escala após a demanda diminuir) com a computação serverless, o fornecedor simplesmente alocará o cálculo adicional para sua função com base no número de requisições que chegam.

Pay-As-You-Go

Na computação serverless, você só paga pelo que você usa. O modelo Pay-As-You-Go provavelmente resultará em economia de custos na maioria dos casos (lembre-se da infraestrutura subutilizada) e se torna particularmente benéfico nos cenários de tráfego inconsistentes descritos anteriormente. O modelo também significa que qualquer otimização de velocidade do seu serviço se traduz diretamente em economia de custos.

O Pay-As-You-Go também é uma vantagem nos serviços PaaS, no entanto, a maioria destes serviços não vão fundo no quesito granularidade de alocação de energia de computação.

Além disso, em um ambiente de serverless, você não precisa fornecer, gerenciar, corrigir ou proteger os servidores. Você está terceirizando o gerenciamento do hardware físico e dos servidores virtuais, sistemas operacionais, redes e segurança para o fornecedor de computação serverless . Isso fornece economia de custos das duas maneiras a seguir:

  • Custo de infraestrutura direta;
  • O custo das operações de TI.

Essa vantagem também existe em qualquer serviço PaaS, e para um serviço FaaS, na verdade, não pode ser tão direto quanto parece. Embora existam benefícios de custos muito claros para não gerenciar servidores, é importante lembrar que as operações normalmente cobrem muito mais do que o gerenciamento de servidores, incluindo tarefas como implantação, monitoramento e segurança de aplicações.

Principais desvantagens

Algumas dessas desvantagens resultam de uma complexidade adicional da arquitetura de aplicações. Outras resultam da falta de maturidade dos tools nos atuais ambientes serverless e dos problemas que acompanham as partes de terceirização do seu sistema.

Complexidade do sistema distribuído

Semelhante à arquitetura de microsserviços, o serverless apresenta uma maior complexidade de sistema e um requisito de comunicação de rede entre as camadas da aplicação. A complexidade adicionada se centra em torno dos dois aspectos principais, a saber:

  • Interfaces implícitas entre os serviços: conforme discutido anteriormente, as funções tornam as mudanças nas aplicações mais fáceis ao permitir versionamento separado dos serviços. Isso, no entanto, introduz um contrato implícito entre diferentes partes do sistema, que poderia ser quebrado por um dos lados. Em uma aplicação monolítica, as mudanças de quebra podem ser facilmente capturadas pelo compilador ou testes de integração. Em um ambiente FaaS, um desenvolvedor poderia fazer uma mudança de ruptura sem consciência do impacto;
  • Rede e filas: em um ambiente FaaS, partes da aplicação se comunicam entre si usando solicitações HTTP ou mecanismos de filas. Isso introduz latência adicional, adiciona uma dependência em serviços de filas específicos, e torna a manipulação de erros e retentativas significativamente mais complexa.

Segurança e monitoramento

Uma vez que as ofertas de computação serverless são novas, suas ferramentas de segurança e monitoramento também o são, e muitas vezes bem específicas para o ambiente serverless e para um determinado fornecedor. Isso introduz mais complexidade no processo de gerenciamento de operações para a aplicação em geral, adicionando um novo tipo de serviço a gerenciar.

Testes

Os testes podem tornar-se mais difíceis em um ambiente serverless devido aos seguintes aspectos:

  • Para fins de testes de integração, às vezes é difícil replicar o fluxo completo baseado na nuvem em uma máquina de teste;
  • Quanto mais distribuído o sistema, mais dependências e pontos de falha são introduzidos, e mais difícil se torna testar cada variação possível destes fluxos;
  • O teste de carga torna-se um aspecto ainda mais crucial para testar a aplicação, já que algumas questões só podem surgir em escala.

Controle de fornecedores

Ao contrário do famoso vendor lock-in, o controle de fornecedores implica que, ao terceirizar uma grande parte do gerenciamento de suas operações, você também renuncia ao controle sobre como essas operações são tratadas. Isso inclui as limitações do serviço, o mecanismo de escalabilidade e a otimização potencial de hospedagem da sua aplicação.

Além disso, o fornecedor tem o controle final sobre o ambiente e as ferramentas, decidindo quando implementar recursos e corrigir problemas (embora no caso do Azure Functions você possa ajudar a resolver problemas contribuindo para o projeto de código aberto).

Multitenancy

Apenas alguns anos atrás, o modelo multitenancy costumava estar no topo da lista de preocupações das organizações que consideravam usufruir da nuvem pública. No entanto, o multitenancy também é o que permite que as nuvens públicas se tornem mais rentáveis e mais inovadoras que os centros de dados privados. Em particular, os benefícios de custo da computação serverless dinamicamente alocada resultam da economia de escala, o que é possível utilizando a mesma infraestrutura para atender a diferentes aplicações de clientes em momentos diferentes.

Atualmente, a maioria das organizações aceitou que os fornecedores públicos de nuvem se comprometeram a assegurar que, como cliente, você obtenha o mesmo isolamento de segurança e alocação de recursos dedicados em uma nuvem pública como faria em um ambiente single-tenant (quando cada instância de uma aplicação é customizada para atender um cliente em específico).

Primeiros passos

A Azure é a plataforma pública de computação em nuvem da Microsoft. Neste artigo, nos concentraremos no serviço nativo chamado Azure Functions, que é a principal oferta da Microsoft para a computação serverless.

O Azure Functions é um FaaS. Conforme discutido anteriormente, em uma oferta típica de PaaS, você é responsável por gerenciar suas camadas de aplicativos e dados, enquanto o fornecedor administra o hardware, middleware, SO, servidores e redes. Em um ambiente FaaS, o fornecedor também gerencia o contexto do aplicativo e você pode se concentrar apenas na implementação de uma função específica, isto é, escrever o código que atinja um objetivo específico.

Uma conta na Azure (billing) é uma conta usada para fins de cobrança e gerenciamento de assinaturas. Uma vez criada a conta terá também acesso ao portal Azure Billing, onde você pode criar e gerenciar suas assinaturas. Existem dois tipos de contas Azure, pessoais e organizacionais:

  • Conta pessoal: é necessário criar uma conta Azure Billing antes de criar uma assinatura. Neste caso, uma conta Azure pode ser criada usando uma conta pessoal da Microsoft (com seu ID de conta);
  • Conta organizacional: poderá ou não ter acesso ao portal de cobrança. Mesmo que não tenha acesso ao billing, ainda poderá acessar os recursos da Azure ao receber permissões sobre uma ou mais assinaturas.

Vejamos algumas maneiras diferentes para acessar uma conta Azure e subscrever para fins de desenvolvimento:

  • Inscreva-se para uma conta de avaliação pessoal gratuita usando uma conta pessoal da Microsoft;
  • Crie uma conta Pay-As-You-Go pessoal usando uma conta pessoal da Microsoft;
  • Use um benefício mensal Azure da assinatura MSDN (a comunidade de desenvolvedores da Microsoft) que vem com uma certa quantidade de créditos mensal da Azure. Você pode usar uma conta Microsoft ou uma conta organizacional que tenha acesso a uma assinatura MSDN;
  • Use uma conta corporativa da Azure (uma conta organizacional).

Para os propósitos deste artigo, faremos uso apenas dos recursos gratuitos do Microsof Azure, a menos que você não submeta milhares de requisições de teste. Logo, se estivermos dentro dos limites default da nossa subscrição, nenhum encargo será aplicado.

Criando uma subscrição

Primeiro, precisamos criar uma subscrição Azure através de alguns passos básicos. Acesse a home do portal Azure (vide seção Links) e crie uma conta (você pode usar uma conta Hotmail ou Outlook para logar, caso já tenha uma). O passo a passo é bem intuitivo, e dados do seu cartão de crédito serão requeridos ao longo do processo, porém é apenas para conferência de informações, nenhuma cobrança será efetuada a menos que você selecione um plano específico.

Quando finalizar, clique no botão “Introdução à assinatura Azure” e será redirecionado para o portal do Azure. Uma vez lá, na caixa de pesquisa superior do canto direito, digite “assinaturas”, selecione a opção que aparecer e, quando for redirecionado para a página de Assinaturas, clique em “Adicionar”. Selecione, então, a oferta “Pago pelo Uso”, tal como demonstrado na Figura 1. Caso seja solicitado atualizar o plano para manter os serviços existentes, selecione a primeira opção fornecida.

Nota: Caso seja solicitado qualquer plano adicional de suporte, basta cancelar selecionando a opção de não desejo contratar
 Selecionando oferta
Pago pelo Uso
Figura 1. Selecionando oferta Pago pelo Uso

Aplicativos de Funções

Você deve ter reparado que existe uma série de opções na barra lateral do portal Azure, dentre as quais temos os “Aplicativos de Funções”. Um aplicativo de função pode ser composto por uma ou mais funções individuais hospedadas em conjunto. Essas funções não precisam ser do mesmo tipo ou mesmo escritas na mesma linguagem.

Ao implantar funções a partir do controlador de códigos ou de um pipeline de delivery contínuo, o aplicativo de função representa a menor unidade de deploy (ou seja, as funções separadas no aplicativo de função não podem ser deployadas de forma independente).

Uma função Azure, por sua vez, consiste em código de função e configuração. O código da função é o que será executado quando a função for acionada. A configuração da função define, entre outras coisas, as conexões de entrada e saída da função. As ligações de entrada determinam quando e como o código da função será acionado. Vamos criar, portanto, nossa primeira função Azure no portal de gerenciamento. Para isso, vá em “ Novo > Computação > Aplicativo de Funções ” e preencha as opções apresentadas tal como vemos na Figura 2. Perceba que basta preencher o nome do aplicativo com algo bem específico, que os demais campos serão automaticamente completados.

Configurando nosso
aplicativo de funções
Figura 2. Configurando nosso aplicativo de funções

O parâmetro “Nome do aplicativo” é o prefixo DNS ao qual sua aplicação será atribuída. Uma vez implantado, seu aplicativo será roteável publicamente através de [SeuNomeDeApp].azurewebsites.net . O nome (prefixo DNS) precisa ser exclusivo no domínio azurewebsites.net.

Na computação serverless Azure, as funções ativadas por HTTP são automaticamente atribuídas a um endpoint público e não requerem um API Gateway. A URL https://[ SeuNomeDeApp].azurewebsites.net será a URL base para os endpoints das suas funções. Observe que você terá que escolher um nome diferente ou anexar um sufixo se o nome que você deseja usar já existe.

Uma vez que tudo estiver devidamente preenchido, basta clicar em “Criar” e em alguns minutos seu serviço estará deployado e disponível para uso. Na dashboard do seu painel você poderá acompanhar o status de deploy, assim como quando o mesmo estiver finalizado.

Para deployar uma função Azure num Aplicativo de Função, uma vez que o mesmo finalize sua implantação, o Portal de Gerenciamento irá redirecioná-lo para a página "Portal de Funções". Vamos explorar alguns dos passos para implantar uma função Azure online:

  • Quando você for redirecionado para as Funções vá até o menu Add (sinal de mais), que abrirá uma página de Início Rápido. Ignoraremos a implantação do Quickstart para que possamos explorar todas as opções disponíveis;
  • Na parte inferior da página, selecione a opção “ Custom function ” (na seção “ Get started on your own);
  • Defina o valor da combo Language como C# e selecione o Scenario como API & Webhooks;
  • Escolha o modelo “ HttpTrigger - C# ”, que criará uma nova função a partir de um modelo de trigger HTTP, com um endpoint HTTP atribuído automaticamente;
  • Escolha um nome para sua função. Este nome se tornará uma parte da URL do endpoint da sua função. Esse nome precisa ser exclusivo no aplicativo de função, mas não em diferentes aplicativos de função;
  • Selecione o valor Anonymous em “ Authorization level ”. Por enquanto, escolheremos "anônimo", o que significa que nosso endpoint HTTP será acessível a qualquer pessoa na URL público que será gerada automaticamente para sua função.

Vide a Figura 3 com base para validar as opções preenchidas até aqui. Após isso, basta clicar no botão Create e você será redirecionado para o portal de desenvolvimento das funções Azure UI, onde poderá, inclusive, editar o código C# da sua função, dentre outras opções de configuração.

Resumo da seleção
de opções para criar nova função Azure
Figura 3. Resumo da seleção de opções para criar nova função Azure

No lado direito do portal, você verá a biblioteca de arquivos que contém o código e a configuração usados em sua função. Os arquivos necessários serão gerados automaticamente a partir do modelo quando você escolher o tipo de função. Você também pode adicionar ou fazer upload de novos arquivos e excluir os arquivos da parte inferior do painel View files.

Esses arquivos são hospedados em seu ambiente de serviço de aplicativo em D:\home\site\wwwroot\[NomeDaSuaFuncao] . Há também um arquivo host.json que está localizado no diretório wwwroot e contém a configuração de tempo de execução compartilhada por todas as funções individuais no seu Aplicativo de Funções.

O modelo de função disparado por HTTP que criamos vem com os seguintes dois arquivos gerados automaticamente: o arquivo run.csx que contém o código da função em si, e o arquivo function.json que contém as configurações da função. Vide na Listagem 1 o código autogerado da nossa função.

Listagem 1. Código autogerado da função em run.csx.

        
        using System.Net;

        public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
        {
        log.Info("C# HTTP trigger function processed a request.");

        // parse query parameter
        string name = req.GetQueryNameValuePairs()
        .FirstOrDefault(q => string.Compare(q.Key, "name", true) == 0)
        .Value;

        // Get request body
        dynamic data = await req.Content.ReadAsAsync<object>();

        // Set name to query string or body data
        name = name ?? data?.name;

        return name == null
        ? req.CreateResponse(HttpStatusCode.BadRequest,
        "Please pass a name on the query string or in the request body")
        : req.CreateResponse(HttpStatusCode.OK, "Hello " + name);
        }
        

Esta função é criada para responder a um trigger de endpoint HTTP. Ela espera um parâmetro chamado name na query da URL ou no corpo da query. Se recuperar um valor de string, como o “ Mundo ” para o parâmetro de name, a função retornará uma resposta HTTP com status OK (200) e uma mensagem " Hello world ". Caso contrário, retornará um status HTTP de Bad Request (400) e uma mensagem solicitando a passagem de um nome na query string ou na mensagem do corpo da requisição.

Caso o leitor queria testar o funcionamento de sua função, basta clicar na seção Test, ao lado da View files . Ela provê uma interface rápida para teste dos endpoints de funções que estamos desenvolvendo, bem como debugging dos resultados HTTP, etc. Vide Figura 4 para exemplo de teste com nossa função de Alô Mundo. A mesma será aberta assim que você clicar no botão “ Run ” acima do código da função.

 Seção Test para testes de URL das funções
Figura 4. Seção Test para testes de URL das funções

Além disso, ao lado do botão Run, temos um link chamado “</> Get function URL ” que, quando clicado, exibirá uma pop-up com uma representação da URL para que possa testar da maneira que desejar (Figura 5).

Recuperando a URL
da função
Figura 5. Recuperando a URL da função

Para testar em um exemplo real, abra uma aba do seu navegador e digite a seguinte URL:


        https://meutestedevmedia01.azurewebsites.net/api/AloMundo?name=DevMedia

Você verá o resultado da requisição, tal como temos na Figura 6.

Testando requisição
da nossa função via browser
Figura 6. Testando requisição da nossa função via browser

A partir daí, alterar qualquer parte do código, ou criar novas funções se torna extremamente simples, até mesmo a adição de novos arquivos csx para contemplar novas funções pode ser feito usando somente a interface web, o que te disponibiliza um ambiente totalmente online, sem a necessidade de IDEs e toda a complexidade de downloads/gerenciamento que temos convencionalmente.

Por exemplo, vamos criar uma segunda função Azure para, agora, passar a receber dois parâmetros (peso e altura) que, por sua vez, serão usados para calcular o índice de massa corpórea (IMC) de uma pessoa. Vide o código da Listagem 2 que deverá substituir o default do arquivo run.csx. Crie a função usando as mesmas definições que usamos para a primeira, dando o nome de “ CalcularIMC ” à mesma.

Listagem 2. Função Azure para calcular IMC.
using System.Net;
        using static System.Math;
        using static System.Convert;

        public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
        {
        log.Info("C# HTTP trigger function processed a request.");

        // parse query parameters
        string peso = req.GetQueryNameValuePairs()
        .FirstOrDefault(q => string.Compare(q.Key, "peso", true) == 0)
        .Value;

        string altura = req.GetQueryNameValuePairs()
        .FirstOrDefault(q => string.Compare(q.Key, "altura", true) == 0)
        .Value;

        // Get request body
        dynamic data = await req.Content.ReadAsAsync<object>();

        // Set peso/altura to query string or body data
        peso = peso ?? data?.peso;
        altura = altura ?? data?.altura;

        if (peso == null)
        {
        log.Error($"Parameter peso missing in HTTP request. RequestUri={req.RequestUri}");
        return req.CreateResponse(HttpStatusCode.BadRequest,
        "Favor informar o parâmetro 'peso' na query string!");
        }

        if (altura == null)
        {
        log.Error($"Parameter altura missing in HTTP request. RequestUri={req.RequestUri}");
        return req.CreateResponse(HttpStatusCode.BadRequest,
        "Favor informar o parâmetro 'altura' na query string!");
        }

        return req.CreateResponse("Seu IMC: " + CalcularIMC(Convert.ToDouble(peso),
        Convert.ToDouble(altura)));
        }

        public static double CalcularIMC(double peso, double altura) {
        double bmi = Math.Pow(peso / altura, 2);
        return Math.Round(bmi, 2);
        }
        

Veja que mantivemos praticamente toda a estrutura original da função Run(), assíncrona, recebendo o mesmo objeto de request e devolvendo um response ao final. Vejamos as principais alterações:

  • Adicionamos os imports (using) estáticos para as classes Math e Convert (operações matemáticas e conversões de tipos, respectivamente);
  • Recebemos agora dois parâmetros, efetuando as mesmas checagens se os mesmos estão presentes na query string de antes;
  • Verificamos também se ambos estão no body do request, caso não venham na query string;
  • Por fim, chamamos a nova função CalcularIMC() para calcular o IMC final com base nos parâmetros recebidos e devolvemos a string de resposta via CreateResponse().

Veja que a função CreateResponse() deve ser declarada como static, isso porque não estamos manipulando objetos no C#, logo ela deve estar sempre disponível após inicialização da classe em si, não carecendo assim de contexto.

Para testar nossa nova função, basta abrir a seção Test novamente, preencher os parâmetros da requisição e clicar no botão de Run, tal como vemos na Figura 7.

Resultado do teste
com nossa nova função
Figura 7. Resultado do teste com nossa nova função

Ou, caso prefira, basta executar a seguinte URL no navegador e teremos o resultado demonstrado pela Figura 8:

https://meutestedevmedia01.azurewebsites.net/api/CalcularIMC?peso=55&altura=1.78
Executando função
IMC no navegador
Figura 8. Executando função IMC no navegador

Functions no Visual Studio

As ferramentas de Funções do Azure estão disponíveis a partir do Visual Studio 2017 Update 3 ou posterior. Para tal, vamos baixar e instalar o Visual Studio executando as seguintes etapas:

  • Baixe o Visual Studio Community gratuitamente via link na seção Links, ou use qualquer uma das edições pagas. (Verifique se a sua máquina de desenvolvimento atende aos requisitos mínimos de instalação);
  • Configure o Visual Studio para usar C# como o idioma principal durante a instalação;
  • Durante o processo de instalação, verifique se as cargas de trabalho da Web e do Azure no instalador do VS estão selecionadas. Isso instalará o SDK do Azure e o SDK das Funções;
  • Faça login no Visual Studio com a mesma conta de organização ou de organização que você usou para criar seu ambiente Azure. Isso facilitará a publicação de seus aplicativos na mesma assinatura do Azure.

Seu Visual Studio IDE agora está pronto para usar para funções Azure. Após isso, o template Funções Azure aparecerá nos modelos de novos projetos do Visual Studio. Para criar um novo projeto de Funções, navegue até o menu “ Arquivo > Novo > Projeto ” e, em Modelos, selecione “ Visual C# > Cloud > Funções Azure ” conforme mostrado na Figura 9.

Criando novo
Figura 9. Criando novo projeto a partir de template Funções Azure

Depois de clicar em OK, um novo projeto de Aplicativo de Função será criado. Abra o painel do Solution Explorer clicando em “ View > Solution Explorer ”. Lá, você verá a nova estrutura de projeto da Aplicativo de Função. Você notará que o projeto recém-criado não contém automaticamente uma função. Os arquivos na árvore do projeto (local.settings.json e host.json) são os arquivos que definem as configurações do projeto inteiro e serão aplicadas a todas as funções adicionadas ao projeto.

Para executar o seu Aplicativo de Função local contra o ambiente Azure que criamos anteriormente, precisamos propagar as configurações AzureWebJobsStorage e AzureWebJobsDashboard para o nosso ambiente Visual Studio local. Para fazer isso, vamos navegar até a função que criamos “MeuTesteDevmedia01”, ao lado dela você notará duas abas: “ Overview ” e “ Platform Features ”, clique nesta última e, em seguida, em “ Application Settings ”. Você verá as configurações com os nomes correspondentes às do arquivo (Figura 10) e poderá copiá-las e colá-las no local.settings.json do seu projeto (Listagem 3).

Listagem 3. Configuração final do local.settings.json.
{
        "IsEncrypted": false,
        "Values": {
        "AzureWebJobsStorage": "DefaultEndpointsProtocol=
        https;AccountName=meutestedevmedibedf;
        AccountKey=ZjVoxKR77uAOBI8/uctGnF/
        fXWvr4PF35QnWADwpXyRLq32ahhPSkcEvSCs1CgvJHipwyheFsgXfpqLcbF3DXw==",
        "AzureWebJobsDashboard":
        "DefaultEndpointsProtocol=https;
        AccountName=meutestedevmedibedf;
        AccountKey=ZjVoxKR77uAOBI8/uctGnF
        /fXWvr4PF35QnWADwpXyRLq32ahhPSkcEvSCs1CgvJHipwyheFsgXfpqLcbF3DXw=="
        }
        }
        
Configurações do
aplicativo no Azure Functions
Figura 10. Configurações do aplicativo no Azure Functions

Para criar uma nova função, basta clicar com o botão direito sobre o projeto, na Solution Explorer, ir em “ Adicionar > Novo Item... > Itens do Visual C# > Azure Functions ” e dar um nome ao arquivo (que será o mesmo nome da função). Digite “CalcularIMC” e, finalmente, clique em “ Adicionar ”.

Aqui seremos novamente questionados sobre o tipo de função a ser criada. Selecione mais uma vez “ Http trigger ” e “ Anonymous ” na combo de “ access rights ”. Clique em OK . O código será praticamente idêntico ao que criamos no portal online.

Para executar a função localmente, basta clicar no botão de Start no topo do Visual Studio, se certificando que o a opção “Debug” está selecionada na combo ao lado. O VS possivelmente exibirá um alerta informando que as ferramentas de debug do Azure Functions são necessárias, bastando selecionar OK para que ele prossiga. Uma janela auxiliar será aberta para subir o projeto localmente e, ao final, você verá algo como a Figura 11.

Inicializando o
Azure Functions localmente
Figura 11. Inicializando o Azure Functions localmente

Por default, seus aplicativos subirão na porta 7071 da sua máquina (caso deseje alterar o valor, modifique a propriedade “ LocalHttpPort ” no arquivo local.setting.json do projeto). Para ver o exemplo funcionando, basta digitar a seguinte URL em seu navegador:

http://localhost:7071/api/CalcularIMC?name=DevMedia

Publicando função para o Azure

Uma vez que finalizar sua implementação, caso deseje publicar sua função para sua conta na nuvem Azure, basta clicar com o botão direito na solução e selecionar a opção “ Publicar... ”. Uma janela com as opções de publicação aparecerá perguntando se deseja criar um novo host na Azure ou usar um existente. Vamos selecionar a opção “ Selecionar Existente ”, tal como mostra a Figura 12.

Publicando função
no Azure – seleção de host
Figura 12. Publicando função no Azure – seleção de host

Clique em Publicar . O Visual Studio se conectará automaticamente à Microsoft ou à conta organizacional com a qual você iniciou sua sessão e recuperará as assinaturas do Azure que você acessou. Escolha a assinatura apropriada sob a opção “ Assinatura ” e o valor “ Grupo de Recursos ” no menu suspenso “ Exibir ”. Em seguida, escolha a Aplicação de Função Azure que criamos (Figura 13).

Selecionando opções
de serviço de assinatura
Figura 13. Selecionando opções de serviço de assinatura

Clique em OK . Revise as informações que o Visual Studio trouxer sobre o host publicado e, em seguida, clique em Publicar . Uma vez finalizado, você pode navegar até o portal online do Azure e visualizar a nova função.

As funções são recursos extremamente poderosos para disponibilizar tarefas rápidas, das quais recursos podem ser desalocados rapidamente no seu ambiente de nuvem. Muito mais pode ser adicionado aos nossos exemplos, como teste tente criar uma nova função no seu ambiente local (com Visual Studio) e efetuar o mesmo cálculo de IMC que fizemos, ou se desafie a novas implementações como calcular a idade de uma pessoa com base no ano e mês de nascimento dela. O segredo é explorar e, quando finalizar cada implementação, publique na nuvem e teste-as.

Links Úteis

Confira também