Fala dataholics, continuando nossa saga sobre Azure Function, hoje veremos como podemos orquestrar elas dentro dos nossos pipelines de dados, seja ela usando Airflow, Azure Data Factory ou outros orquestradores de mercado, no post de hoje veremos sobre Azure Data Factory, veremos também algumas limitações e erros comuns.
No post de hoje usaremos o Azure Data Factory para chamar nossa Azure Function e tratar dados do Json retornado, podendo ser integrado com outros fluxos ou despejado no Data Lake.
Usarei o termo ADF para abreviar Azure Data Factory.
O que veremos nesse post:
Linked Service Azure Key Vault
Linked Service Azure Function
Parametrizando Linked Service
Chamando uma Azure Function
Usando variáveis dinâmicas no ADF
Tratando erros e JSON
ADF - DEBUG e logs
Problema de timeout Load Balancer para Function Sync - 4 min
Problema timeout Function App - 10 min
Linked Service Azure Key Vault
Linked Services no ADF são as conexões para fontes de dados externas ou serviços, existe uma diversidade de conectores prontos para você utilizar, para esse post usaremos os 2 linked services abaixo.
Vamos criar nosso linked service para Azure Key Vault, primeiramente você precisa ter criado uma Azure Key Vault no seu ambiente e dar acesso do ADF poder conectar.
Essa é a Key Vault da nossa demo, não tem segredos para criar.
Se você ainda não tem familiaridade com Key Vault, entenda ela como um cofre, onde você pode armazenar senhas e conexões seguramente, utilizaremos ela para armazenar a chave de acesso da nossa Azure Function.
Na aba Secrets, já tenho criado 2 secrets, uma usaremos para conectar o ADF na Azure Function.
Para criar o Linked Service para o Azure Key Vault basta seguir esse caminho dentro do ADF.
Na etapa de criação você precisa se atentar ao método de conexão entre o ADF e Key Vault, o mais comum é utilizar o System Assigned Managed Identity.
Quando você usa esse método, basta você ir ao seu recurso da Key Vault e liberar os devidos acessos para o object id do ADF.
Para dar acesso na Key Vault geralmente é via Access Policies, mas dependendo da configuração, também pode ser via RBAC na página IAM, abaixo a policy que libera o acesso do ADF para fazer GET e LIST.
Pronto, pode criar seu Linked Service, para testar basta clicar em Test Connection.
Linked Service Azure Function
Agora vamos criar nosso Linked Service para nossa Azure Function.
Detalhe que na hora de buscar Azure Function ela estará na aba de Compute.
Na criação do linked service para Azure Function usaremos alguns parâmetros que serão enviados pelo pipeline.
Note que estou usando parâmetros para informar a URL da nossa Function e o Secret que possui a chave de acesso da nossa function, apontando para a nossa Key Vault que acabamos de criar. Criando dessa maneira posso reaproveitar esse linked service para chamar qualquer function, basta no pipeline informar a URL e nome da Secret com as informações para autenticação.
Nesse trecho final é onde declaramos nossos parâmetros, assim qualquer Dataset ou Pipeline que utilize esse Linked Service precisa enviar esses parâmetros.
Chamando uma Azure Function
Agora com os Linked Services já criados, podemos acionar a nossa Azure Function através de um pipeline.
Esse é o pipeline que vamos criar:
1x Atividade para chamar a Azure Function
1x Atividade para caso de falha ela extrair a falha do pipeline e concatenar uma mensagem
1x Atividade para caso de sucesso ela preencher uma variável
É um pipeline bem simples, mas que vamos conseguir usar algumas funções legais.
Aqui são as configurações da atividade que irá chamar a Azure Function, repare que aparece novos campos nas propriedades Linked service properties, aqui informamos nossa URL e o nome da Secret para buscar a chave de acesso na Key Vault.
O nome da function estamos passando fixo, embora, poderia ser dinâmico também, exemplo, vindo de outras atividades.
Por fim o método que usaremos é GET, pois pegaremos dados dessa API.
Na nossa atividade de Set Variable em caso de sucesso na atividade anterior, usaremos um valor dinâmico para preencher a variável.
@json(activity('GetCEP').output.response)[0].cidade
Basicamente estamos convertendo o resultado para JSON, pegando o item 0 do Array e o campo cidade do Json, veremos melhor no debug.
Na nossa atividade de falha também estamos usando valores dinâmicos, para a mensagem de falha concatenaremos ela com um texto padrão e recuperar a mensagem de erro no retorno.
Vamos para o DEBUG:
Você pode rodar o seu pipeline sem salvar ou publicar ele usando o botão DEBUG, quando você utilizar esse método pode acompanhar os logs na aba Output. Se você usar o método Triger Now precisará ir ao Monitor do ADF para ver a execução.
Bom nosso pipeline falhou, vejamos o retorno.
Observação: todas as atividades sempre têm aquelas duas setinhas, uma para INPUT e outra para OUTPUT e você consegue acessar elas para ver mais detalhes, muito útil durante investigação de falhas.
INPUT: Geralmente os parâmetros de entrada.
OUTPUT: Geralmente o retorno do ADF sobre consumo de recursos mais retorno de logs em geral.
E abaixo o retorno da nossa atividade de falha, note que a mensagem saiu como planejamos.
Lembrando que é um exemplo para simplificar a explicação.
Fail Message:
@concat('Falha nesse trem: ',activity('GetCEP').Error.message)
Error code:
@activity('GetCEP').Error.errorCode
Bom, sabemos que o erro ocorreu, pois não informamos o CEP, então, como podemos informar o CEP numa requisição GET se não tem parâmetros nem body para ser informado na atividade de Azure Function?
Nesse caso colocaremos junto ao nome da Function separado por ?.
Vamos DEBUGAR de novo:
Agora temos sucesso, vamos olhar o OUTPUT da nossa atividade que chamou a Azure Function.
Note que temos um Response com um ARRAY e dentro temos um JSON, o que faremos na próxima atividade é extrair o campo cidade de dentro desse retorno.
Esse é o OUTPUT da atividade SET VARIABLE.
Usamos essa função para chegar nesse resultado:
@json(activity('GetCEP').output.response)[0].cidade
Espero que tenha gostado desse exemplo prático com ADF.
Problema de timeout Load Balancer para Function Sync
Temos um problema pouco conhecido quando usamos uma Azure Function com trigger de HTTP em modo Sync, que é o timeout do Load Balancer.
O que seria modo Sync?
Modo Sync é quando faço uma requisição e enquanto ela não finalizar o processo que disparou fica esperando, o contrário de Sync seria o Async, faço uma requisição e não preciso aguardar o retorno.
O que seria essa limitação do Load Balancer?
Basicamente para conectar na Azure Function temos um Load Balancer que não é visível para nós, esse Load balancer tem um limite de 230 segundos.
Vejamos na prática:
Na minha API de CEP adicionei um SLEEP de 240 segundos, ou seja, uma espera de 4 minutos para iniciar a executar a função.
Agora note que depois de 4 minutos tomaremos o seguinte erro:
Call to provided Azure function 'fn_http_trigger?cep=12246-875' failed with status-'GatewayTimeout' while invoking 'GET' on 'https://demofunctionappstorage.azurewebsites.net' and message - '504.0 GatewayTimeout'.
Isso é um problema geral, não há como contornar, se você esta usando function HTTP Sync ela precisa retornar em menos de 4 minutos, o que faz muito sentido para a maioria dos cenários.
Fazendo um teste via Python local para validar que o timeout não é somente via ADF:
Erro:
502 - Web server received an invalid response while acting as a gateway or proxy server.</h2>\r\n <h3>There is a problem with the page you are looking for, and it cannot be displayed. When the Web server (while acting as a gateway or proxy) contacted the upstream content server, it received an invalid response from the content server.
Uma possibilidade de contorno é estudar sobre Async HTTP APIs:
Problema timeout Function App
Ah, Reginaldo, mas vi na documentação que o timeout da Function App no plano Consumption é de até 10 minutos.
Sim, de fato, o tempo total que uma Function pode rodar nesse modelo é de até 10 minutos, isso serve para qualquer tipo de Function, exemplo function com trigger de Timer.
A limitação que vimos anteriormente é específica para function HTTP Sync, quando usamos Function com trigger Timer, por exemplo, ela pode rodar por mais tempo, embora, entraremos em outra limitação que é o timeout da Function App.
Vou alterar minha function de Timer Trigger adicionando uma espera de 11 minutos.
Ops, tomamos erro de timeout com apenas 5 minutos!
Sim, isso mesmo, como na própria documentação diz, o default é de 5 minutos e o máximo 10 minutos.
Para alteramos essa configuração precisamos arrumar o parâmetro functionTimeout no arquivo host.json.
Agora, vamos validar novamente nossa function:
Estouramos os 10 minutos agora, ou seja, é possível que ela rode em mais de 4 minutos, pois ela não é uma function HTTP Sync, mas precisa finalizar em até 10 minutos.
Bom, mas deu 10 minutos, pois, na configuração do functionTimeout informamos 10 minutos, e se colocarmos 20 minutos?
Ajustei o parâmetro para 20 minutos agora.
Após publicado, veremos que nossa Function App ficara com erro, enquanto não corrigir, nenhuma function irá rodar.
Resumo
No post de hoje vimos como orquestrar nossas Azure Functions utilizando o Azure Data Factory, aprendemos algumas técnicas de manipulação de retorno de dados e também sobre algumas limitações cruciais quando estamos usando Azure Function.
Se atentar ao timeout para funções HTTP Sync, ela precisa retornar em até 4 minutos.
Se atentar ao timeout geral para o plano Consumption de 10 minutos.
Espero que tenha gostado.
Fique bem e até a próxima.
Referências:
https://ochzhen.com/blog/pass-parameters-to-azure-function-from-adf#:~:text=Azure%20Function%20parameters%20can%20be,used%20to%20invoke%20the%20endpoint (usando parametros no ADF para chamar Azure Function)
Comments