Num cenário em que as exigências tecnológicas crescem continuamente, as organizações procuram soluções simples, eficientes e adaptáveis para responder a novos desafios.
É precisamente neste contexto que entram as Azure Functions, uma solução de computação serverless do Microsoft Azure.
Esta tecnologia permite executar blocos de código de forma simples e escalável, sem necessidade de gerir servidores ou infraestrutura.
Onde é que as Azure Functions Podem Fazer a Diferença?
As Azure Functions destacam-se por reduzirem a complexidade do desenvolvimento e da gestão de aplicações.
Isto acontece porque o Azure gere automaticamente a infraestrutura. Desta forma, as equipas podem concentrar-se no desenvolvimento das funcionalidades necessárias.
Além disso, as Azure Functions permitem criar aplicações e microsserviços leves, modulares e escaláveis, que respondem a diferentes eventos.
Entre estes eventos, destacam-se pedidos HTTP, alterações em bases de dados, mensagens em filas de espera e tarefas agendadas.
Por outro lado, as Azure Functions permitem a integração com outros serviços do ecossistema Azure e com APIs externas.
Adicionalmente, suportam várias linguagens de programação, como C#, JavaScript e Python. Assim, facilitam a adaptação por parte das equipas de desenvolvimento.
Python e Azure Functions: A Parceria Ideal para Soluções Inovadoras
No desenvolvimento de Azure Functions com Python, as equipas podem criar o código localmente, utilizando diferentes ferramentas.
Por exemplo, podem recorrer ao Visual Studio Code, ao PyCharm ou ao terminal, através das Azure Functions Core Tools.
Posteriormente, publicam o código na cloud do Microsoft Azure.
Além disso, a integração com plataformas como GitHub, Azure DevOps ou GitLab permite estabelecer um fluxo contínuo de desenvolvimento, testes e publicação.
Automatização com CI/CD
Neste contexto, a utilização de pipelines de CI/CD facilita a automatização de tarefas essenciais.
Estes processos permitem integrar, testar e entregar código de forma contínua. Assim, simplificam as tarefas desde a verificação até à publicação de versões atualizadas.
Consequentemente, as equipas conseguem melhorar a consistência e a rapidez do processo de desenvolvimento.
Monitorização e Diagnóstico
Paralelamente, o Azure recolhe logs e métricas em tempo real, fornecendo visibilidade sobre o comportamento das funções.
Desta forma, as equipas conseguem acompanhar a execução do código e identificar eventuais problemas.
Além disso, esta monitorização simplifica o diagnóstico e contribui para uma manutenção mais eficiente das aplicações.
Estruturas de Programação em Azure Functions
Modelo v1 vs. Modelo v2
O desenvolvimento de Azure Functions em Python pode seguir dois modelos principais: v1 e v2.
O modelo v1, mais antigo, recorre fortemente a ficheiros de configuração externos, como o function.json. Assim, apresenta uma menor integração entre a configuração e o código.
Por outro lado, o modelo v2 apresenta uma abordagem mais moderna e centrada no código. Neste caso, os programadores podem definir as funções diretamente em Python, utilizando decorators.
Desta forma, o modelo v2 simplifica a estrutura dos projetos e proporciona uma melhor experiência de desenvolvimento.
A escolha entre os dois modelos deve considerar diferentes fatores. Entre eles, destacam-se a complexidade da aplicação, o grau de personalização necessário e a preferência por uma abordagem mais declarativa ou orientada ao código.
Modelo v1
No modelo v1, cada função ocupa uma pasta própria e utiliza dois ficheiros principais:
__init__.py: Contém a lógica da função desenvolvida em Python.function.json: Define a configuração da função, nomeadamente os triggers e bindings.
Desta forma, o modelo separa a lógica da aplicação das respetivas configurações.
Estrutura de um Projeto no Modelo v1
Segue-se uma estrutura típica de um projeto desenvolvido com o modelo v1:
MyFunctionApp/
│── host.json
│── local.settings.json
│
├── HttpTriggerFunction/
│ ├── __init__.py
│ └── function.json
│
└── XXXXXXXXFunction2/
├── __init__.py
└── function.json
O exemplo seguinte ilustra como implementar uma função HTTP simples no Modelo v1, apresentando de forma clara a implementação do código nos ficheiros __init.py__ e function.json.
Além disso, esta organização torna o modelo particularmente útil em protótipos ou projetos de pequena dimensão.
Assim, as equipas conseguem desenvolver soluções simples de forma rápida, sobretudo quando a estrutura do código não exige uma modularização complexa.
No entanto, à medida que a complexidade aumenta, o modelo v1 pode apresentar limitações.
Por exemplo, projetos com múltiplas funções, lógica partilhada e testes automáticos podem exigir uma estrutura mais flexível.
Nesses casos, recomenda-se a utilização do modelo v2, que oferece uma arquitetura mais modular e escalável.
Modelo v2
O modelo v2 surge como uma evolução do modelo anterior, procurando ultrapassar algumas das suas limitações em projetos mais complexos.
Neste modelo, várias funções podem coexistir num único ficheiro Python.
Além disso, os programadores declaram os triggers e bindings diretamente no código, através de decorators.
Desta forma, deixam de ser necessários ficheiros function.json separados para cada função.
Consequentemente, o projeto torna-se mais organizado e o código mais legível, facilitando também a manutenção.
Estrutura de um Projeto no Modelo v2
No exemplo seguinte, toda a lógica das funções encontra-se no ficheiro function_app.py:
MyFunctionApp/
│── host.json
│── local.settings.json
│── function_app.py
│── requirements.txt
No exemplo seguinte, a função acionada por um Timer Trigger é definida através de um decorator, que especifica a sua agenda de execução. Dentro da função main, implementa-se a lógica que será executada sempre que o trigger dispara.
Utiliza-se logging.info() para registar mensagens nos logs, uma prática fundamental em aplicações serverless, onde não existe uma interface direta para ver o output. Os logs permitem monitorizar a execução, detetar erros e manter informações de auditoria. Neste caso, cada disparo do Timer Trigger regista a mensagem “Hello World! A função Timer Trigger foi executada.”, confirmando que a função correu corretamente.
import azure.functions as func
import logging
# Criar a Function App (obrigatório no V2)
app = func.FunctionApp()
# Função Timer Trigger no Modelo V2
# Executa a cada 5 minutos
@app.timer_trigger(schedule="0 */5 * * * *", arg_name="mytimer")
def timer_main(mytimer: func.TimerRequest) -> None:
"""
Função Timer Trigger que escreve 'Hello World' nos logs a cada 5 minutos.
"""
logging.info("Hello World! A função Timer Trigger foi executada.")
Caso tenha por objetivo adicionar uma função, por exemplo, com HTTP Trigger, a seguir é possível observar como seria a implementação da mesma:
import azure.functions as func
import logging
app = func.FunctionApp()
# Função Timer Trigger que executa a cada 5 minutos
@app.timer_trigger(schedule="0 */5 * * * *", arg_name="mytimer")
def timer_main(mytimer: func.TimerRequest) -> None:
logging.info("Hello World! Timer Trigger executada.")
# Função HTTP Trigger que responde a pedidos HTTP (GET/POST)
@app.route(route="hello", methods=["GET", "POST"])
def http_main(req: func.HttpRequest) -> func.HttpResponse:
name = req.params.get("name")
if not name:
try:
body = req.get_json()
if isinstance(body, dict):
name = body.get("name")
except ValueError:
name = None
if name:
return func.HttpResponse(f"Olá, {name}!", status_code=200)
return func.HttpResponse(
"Por favor, envia o parâmetro 'name' na query ou no corpo.",
status_code=400,
)
Como podemos observar, o código define duas funções independentes no mesmo ficheiro.
Por um lado, a função timer_main executa-se automaticamente a cada cinco minutos e regista uma mensagem nos logs.
Por outro lado, a função http_main responde a pedidos HTTP.
Além disso, permite receber opcionalmente um parâmetro name para personalizar a resposta.
Desta forma, o exemplo demonstra como várias funções podem coexistir num único ficheiro, sem necessidade de um main central.
Consequentemente, esta abordagem simplifica a organização do código e facilita o desenvolvimento de aplicações com diferentes funcionalidades.
Blueprint
No Modelo V2 das Azure Functions em Python, os blueprints constituem uma forma de modularizar e oNo modelo v2 das Azure Functions em Python, os Blueprints permitem modularizar e organizar funções fora do núcleo principal da aplicação.
Um Blueprint é uma classe que permite registar funções de forma independente.
Posteriormente, o programador associa essas funções à aplicação principal, permitindo que o runtime as reconheça.
Principais Vantagens dos Blueprints
Entre os principais benefícios, destacam-se:
- Modularização da aplicação: Permite dividir as funcionalidades em componentes e distribuir funções por vários ficheiros Python.
- Reutilização de código: Facilita a criação de interfaces públicas extensíveis e a reutilização de APIs e lógica comum.
- Organização e manutenção: Torna o código mais limpo, estruturado e fácil de manter.
Estrutura de um Projeto com Blueprints
A estrutura seguinte representa uma Azure Function desenvolvida com recurso a Blueprints:
<project_root>/
│
├── function_app.py # Regista os blueprints
├── http_blueprint.py # Blueprint com funções HTTP
├── outro_blueprint.py # Outro módulo com funções específicas
├── host.json
├── local.settings.json
├── requirements.txt
├── .funcignore
A seguir está representado um Blueprint simples, que contém uma função HTTP que responde a pedidos de rota ‘/hello’.
http_blueprint.py
import azure.functions as func
bp = func.Blueprint()
@bp.route(route="hello")
def hello(req: func.HttpRequest) -> func.HttpResponse:
user = req.params.get("user")
return func.HttpResponse(f"Olá, {user or 'mundo'}!")
Aquando da definição do Blueprint, é necessário registá-lo na aplicação principal para que as rotas fiquem acessíveis pelo Azure Functions runtime. O exemplo seguinte mostra como importar o módulo onde o Blueprint está definido e registar as funções associadas ao mesmo numa instância da FunctionApp.
function_app.py
import azure.functions as func
from http_blueprint import bp
app = func.FunctionApp()
app.register_functions(bp)
Desta forma, as rotas definidas no Blueprint ficam acessíveis através da aplicação principal.
Além disso, esta abordagem permite separar funcionalidades e responsabilidades em diferentes módulos.
O modelo v2 é especialmente vantajoso em projetos com múltiplas funções e complexidade crescente.
Por isso, torna-se uma opção interessante para equipas maiores que precisam de trabalhar em paralelo.
Consequentemente, contribui para melhorar a escalabilidade, organização e manutenção do código.
O Equilíbrio entre Azure Functions e Python: Vantagens e Desafios
Para escolher a solução mais adequada, é fundamental compreender as vantagens e limitações das Azure Functions e da sua implementação em Python.
Desta forma, as organizações conseguem tomar decisões mais informadas, de acordo com os requisitos técnicos de cada projeto.

Modelos de Pagamento
As Azure Functions disponibilizam diferentes opções de alojamento e pagamento.
Neste contexto, o artigo original destaca dois modelos de pagamento do tipo pay-as-you-go: o Consumption Plan e o Flex Consumption Plan.
Consumption Plan
No Consumption Plan, o utilizador paga pelo tempo de execução e pelo número total de execuções das funções.
Além disso, o plano apresenta uma oferta gratuita mensal de 1 milhão de execuções e 400 000 GB-segundos.
Este plano tem um limite de 1,5 GB de memória por instância.
Por outro lado, o tempo máximo de execução por função é, por defeito, de cinco minutos, podendo aumentar até dez minutos através de configuração.
Flex Consumption Plan
O Flex Consumption Plan representa uma opção mais recente e oferece funcionalidades adicionais.
Entre elas, destacam-se as instâncias Always Ready, a maior flexibilidade na configuração da memória e a integração com redes virtuais (VNET).
Além disso, este plano pode apresentar custos superiores, dependendo da configuração e da utilização.
Por outro lado, permite maior controlo sobre os recursos e o desempenho.
Por isso, a Microsoft recomenda o Flex Consumption Plan para cenários serverless que exigem maior flexibilidade e capacidade de configuração.
A Experiência da B2F com Azure Functions
Na B2F, desenvolvemos projetos que demonstram o valor da utilização de Azure Functions com Python.
Estes projetos evidenciam não só o desempenho robusto e a flexibilidade da solução, mas também a sua capacidade de integração com plataformas externas.
Por exemplo, a utilização de REST APIs permite estabelecer ligações entre diferentes sistemas e executar processos ETL (Extract, Transform and Load).
Desta forma, as organizações conseguem automatizar tarefas e interligar sistemas heterogéneos.
Além disso, esta integração contribui para impulsionar a transformação digital de forma escalável.
Consequentemente, pode promover uma redução significativa dos custos operacionais.
Investir em Azure Functions representa, assim, um passo importante para empresas que procuram manter a competitividade.
Além disso, permite ganhar agilidade operacional, reduzir custos com infraestruturas subutilizadas e acelerar o ciclo de inovação.
Desta forma, as organizações conseguem transformar ideias em serviços escaláveis de forma rápida e eficiente.
Este é o momento ideal para aproveitar o potencial das Azure Functions, contando com a B2F como parceira estratégica na transformação digital.
