Quickstart: Processar eventos em tempo real usando o Funções do Azure

Neste artigo, utiliza o Azure Developer CLI (azd) para criar uma função de disparo nos Event Hubs para processamento de eventos em tempo real no Funções do Azure. Depois de verificar o código localmente, implementa-o numa nova aplicação de funções serverless a correr num plano Flex Consumption no Azure.

O código-fonte do projeto utiliza azd para criar a aplicação de funções e os recursos relacionados e para desplegar o seu código no Azure. Esta implementação segue as melhores práticas atuais para implementações Funções do Azure seguras e escaláveis.

Por defeito, o plano Flex Consumption segue um modelo de faturação de pagamento pelo que usar , o que significa que pode completar este artigo e apenas incorrer num pequeno custo de alguns cêntimos USD ou menos na sua conta Azure.

Este artigo suporta a versão 4 do modelo de programação Node.js para o Funções do Azure.

Este artigo suporta a versão 2 do modelo de programação Python para o Funções do Azure.

Pré-requisitos

Inicializar o projeto

Use o azd init comando para criar um projeto de código local do Funções do Azure a partir de um modelo.

No terminal local ou prompt de comando, execute este azd init comando em uma pasta vazia:

azd init --template functions-quickstart-dotnet-azd-eventhub -e eventhub-dotnet

Este comando extrai os arquivos de projeto do repositório de modelos e inicializa o projeto na pasta atual. O -e sinalizador define um nome para o ambiente atual. No azd, o ambiente mantém um contexto de implantação exclusivo para seu aplicativo e você pode definir mais de um. O nome do ambiente também é usado no nome do grupo de recursos que crias no Azure.

No terminal local ou prompt de comando, execute este azd init comando em uma pasta vazia:

azd init --template functions-quickstart-typescript-azd-eventhub -e eventhub-ts

Este comando extrai os arquivos de projeto do repositório de modelos e inicializa o projeto na pasta atual. O -e sinalizador define um nome para o ambiente atual. No azd, o ambiente mantém um contexto de implantação exclusivo para seu aplicativo e você pode definir mais de um. O nome do ambiente também é usado no nome do grupo de recursos que crias no Azure.

No terminal local ou prompt de comando, execute este azd init comando em uma pasta vazia:

azd init --template functions-quickstart-python-azd-eventhub -e eventhub-py

Este comando extrai os arquivos de projeto do repositório de modelos e inicializa o projeto na pasta atual. O -e sinalizador define um nome para o ambiente atual. No azd, o ambiente mantém um contexto de implantação exclusivo para seu aplicativo e você pode definir mais de um. O nome do ambiente também é usado no nome do grupo de recursos que crias no Azure.

Criar e ativar um ambiente virtual

Na pasta raiz, execute estes comandos para criar e ativar um ambiente virtual chamado .venv:

python3 -m venv .venv
source .venv/bin/activate

Se o Python não instalar o pacote venv na sua distribuição Linux, execute o seguinte comando:

sudo apt-get install python3-venv

No terminal local ou prompt de comando, execute este azd init comando em uma pasta vazia:

azd init --template functions-quickstart-java-azd-eventhub -e eventhub-java

Este comando extrai os arquivos de projeto do repositório de modelos e inicializa o projeto na pasta atual. O -e sinalizador define um nome para o ambiente atual. No azd, o ambiente mantém um contexto de implantação exclusivo para seu aplicativo e você pode definir mais de um. O nome do ambiente também é usado no nome do grupo de recursos que crias no Azure.

No terminal local ou prompt de comando, execute este azd init comando em uma pasta vazia:

azd init --template functions-quickstart-javascript-azd-eventhub -e eventhub-js

Este comando extrai os arquivos de projeto do repositório de modelos e inicializa o projeto na pasta atual. O -e sinalizador define um nome para o ambiente atual. No azd, o ambiente mantém um contexto de implantação exclusivo para seu aplicativo e você pode definir mais de um. O nome do ambiente também é usado no nome do grupo de recursos que crias no Azure.

No terminal local ou prompt de comando, execute este azd init comando em uma pasta vazia:

azd init --template functions-quickstart-powershell-azd-eventhub -e eventhub-ps

Este comando extrai os arquivos de projeto do repositório de modelos e inicializa o projeto na pasta atual. O -e sinalizador define um nome para o ambiente atual. No azd, o ambiente mantém um contexto de implantação exclusivo para seu aplicativo e você pode definir mais de um. O nome do ambiente também é usado no nome do grupo de recursos que crias no Azure.

Criar recursos do Azure

Antes de poderes executar a tua função localmente, precisas de criar um namespace e hub de Event Hubs no Azure. Use azd provision para criar estes recursos e configurar as suas definições locais adicionando o ficheiro delocal.settings.json necessário.

  1. Execute o seguinte comando para entrar no Azure:

    azd auth login
    

    Siga as instruções para autenticação usando a sua conta Azure.

  2. A partir da pasta raiz, execute o seguinte comando para criar os seus recursos Azure:

    azd provision
    
  3. Quando solicitado, forneça estes parâmetros de implantação necessários:

    Parâmetro Descrição
    Subscrição do Azure Subscrição na qual cria os seus próprios recursos.
    Localização do Azure Região do Azure na qual criar o grupo de recursos que contém os novos recursos do Azure. Apenas as regiões que atualmente suportam o plano Flex Consumption são mostradas.
    vnetEnabled Use um valor de False para evitar o sobrecusto adicional de criar recursos de rede virtual.

    O azd provision comando cria os recursos Azure necessários, incluindo um namespace e hub Event Hubs, uma aplicação para a função Flex Consumption, Application Insights e uma conta de armazenamento. Também configura o seu ficheiro de local.settings.json com a informação de ligação ao Event Hubs.

Executar no seu ambiente local

  1. Numa janela de terminal separada, inicie o emulador de armazenamento Azurite:

    azurite
    

    O processo local Functions host utiliza o emulador Azurite para a ligação interna de armazenamento (AzureWebJobsStorage) exigida pelo runtime.

  1. Para iniciar a aplicação de funções, execute estes comandos num terminal ou no prompt de comandos para navegar até à src pasta do projeto e iniciar a aplicação de funções:

    cd src
    func start
    
  1. Para iniciar a aplicação de funções, execute este comando num terminal ou no prompt de comandos:

    func start
    
  1. Para construir e iniciar a aplicação de funções, execute estes comandos num terminal ou no prompt de comandos:

    mvn clean package
    mvn azure-functions:run
    
  1. Para instalar dependências e iniciar a aplicação de funções, execute estes comandos num terminal ou prompt de comandos:

    npm install
    npm start  
    
  1. Para instalar dependências e iniciar a aplicação de funções, execute estes comandos num terminal ou prompt de comandos:

    cd src
    npm install
    npm start  
    
  1. Para iniciar a aplicação de funções, execute este comando num terminal ou no prompt de comandos:

    func start
    
  1. Se solicitado, permita que as Ferramentas Centrais (func.exe) sejam chamadas através do firewall.

  2. Quando o anfitrião Functions começa na pasta local do projeto, ele escreve informações sobre as suas funções na saída do terminal.

    Este exemplo inclui uma função de ativação de temporizador que gera automaticamente artigos de notícias a cada 10 segundos e os envia para os Centros de Eventos. A função de disparo dos Event Hubs processa então estes eventos e realiza análise de sentimento e acompanhamento de envolvimento.

    Vê uma saída semelhante a este exemplo:

     [2026-03-02T22:37:30.151Z] Executing 'Functions.EventHubsTrigger'
     [2026-03-02T22:37:30.159Z] Trigger Details: PartitionId: 24, OffsetString: 0, EnqueueTimeUtc: 2026-03-02T22:37:29.1790000+00:00, SequenceNumber: 0, Count: 1, Offset: 0, PartionId: 24
     [2026-03-02T22:37:30.169Z] ⭐ High-engagement article NEWS-20260302-0580CB82 (Views: 6123, Sentiment: 0.57) featured!
     [2026-03-02T22:37:30.174Z] 🔥 Viral article: NEWS-20260302-0580CB82 - 6,123 views
     [2026-03-02T22:37:30.181Z] 🌟 Featured article: NEWS-20260302-0580CB82
     [2026-03-02T22:37:30.185Z] ✅ Successfully processed article NEWS-20260302-0580CB82 - 'Technology Breakthrough in Renewable Energy Technology' by Sarah Johnson
     [2026-03-02T22:37:30.191Z] 📰 Processed 1 news articles, 0 failed in batch of 1
     [2026-03-02T22:37:30.196Z] 📊 NEWS BATCH SUMMARY: 1 articles | Total Views: 6,123 | Avg Views: 6,123 | Avg Sentiment: 0.57 | Status: [Featured: 1]
     [2026-03-02T22:37:30.200Z] 📂 Top Categories: [Health: 1] | Top Sources: [Innovation Weekly: 1]
     [2026-03-02T22:37:30.204Z] 🔥 Viral articles in batch: 1
     [2026-03-02T22:37:30.207Z] Executed 'Functions.EventHubsTrigger' (Succeeded, Duration=55ms)
     
  3. Quando terminar, pressione Ctrl+C na janela do terminal para interromper o processo do func.exe host.

  4. Fecha a janela por onde a Azurite está a correr.

  1. Execute deactivate para desligar o ambiente virtual.

Rever o código (opcional)

Pode rever o código que define a função de disparo do Event Hubs:

using System.Text.Json;
using Azure.Messaging.EventHubs;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;

namespace function_app;

public class EventHubsTrigger
{
    private readonly ILogger<EventHubsTrigger> _logger;
    private readonly NewsProcessingService _newsService;

    public EventHubsTrigger(ILogger<EventHubsTrigger> logger, NewsProcessingService newsService)
    {
        _logger = logger;
        _newsService = newsService;
    }

    [Function(nameof(EventHubsTrigger))]
    public async Task Run([EventHubTrigger("news", Connection = "EventHubConnection")] EventData[] input)
    {
        var processedArticles = new List<NewsArticle>();
        var failedEvents = 0;
        
        foreach (var message in input)
        {
            try
            {
                var messageBody = message.EventBody.ToString();

                // Parse the news article event
                var article = ParseNewsArticleEvent(messageBody);

                if (article != null)
                {
                    processedArticles.Add(article);
                }
                else
                {
                    failedEvents++;
                }
            }
            catch (Exception ex)
            {
                failedEvents++;
                _logger.LogWarning($"Error processing message: {ex.Message}");
            }
        }

        // Log summary of this execution
        _logger.LogInformation($"📰 Processed {processedArticles.Count} news articles, {failedEvents} failed in batch of {input.Length}");

Pode consultar o projeto modelo completo aqui.

package com.function;

import com.microsoft.azure.functions.*;
import com.microsoft.azure.functions.annotation.*;

import java.time.Instant;
import java.util.*;
import java.util.logging.Logger;

/**
 * Azure Function that processes messages from an input Event Hub,
 * adds metadata, and sends processed messages to an output Event Hub.
 */
public class EventHubsTriggerFunction {

    @FunctionName("EventHubsTrigger")
    public void run(
            @EventHubTrigger(
                name = "messages",
                eventHubName = "%INPUT_EVENTHUB_NAME%",
                connection = "EventHubConnection",
                cardinality = Cardinality.MANY)
            List<String> messages,
            @EventHubOutput(
                name = "output",
                eventHubName = "%OUTPUT_EVENTHUB_NAME%",
                connection = "EventHubConnection")
            OutputBinding<List<String>> output,
            final ExecutionContext context) {

        Logger logger = context.getLogger();
        logger.info(String.format("🔄 Event hub function processing %d message(s)", messages.size()));

        List<String> processedMessages = new ArrayList<>();

        for (String message : messages) {
            try {
                logger.info("📨 Processing event: " + message);

                // Create processed message with additional metadata
                String processedMessage = String.format(
                    "{\"id\":\"%s\",\"message\":%s,\"timestamp\":\"%s\"}",
                    UUID.randomUUID().toString(),
                    message,
                    Instant.now().toString());

                processedMessages.add(processedMessage);
                logger.info("\u2728 Message processed: " + processedMessage);

            } catch (Exception e) {
                logger.severe("\u274C Error processing message: " + e.getMessage());
            }
        }

        // Send processed messages to output Event Hub
        if (!processedMessages.isEmpty()) {
            output.setValue(processedMessages);
            logger.info(String.format("📤 Sent %d message(s) to output Event Hub", processedMessages.size()));
        }
    }
}

Pode consultar o projeto modelo completo aqui.

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

const eventHubOutput = output.eventHub({
    connection: 'EventHubConnection',
    eventHubName: '%OUTPUT_EVENTHUB_NAME%'
});

async function EventHubsTrigger(messages, context) {
    context.log(`🔄 Event hub function processing ${messages.length} message(s)`);
    
    const processedMessages = [];
    
    for (const message of messages) {
        try {
            // Parse the incoming message
            const eventData = typeof message === 'string' ? JSON.parse(message) : message;
            context.log('📨 Processing event:', eventData);
            
            // Create processed message with additional metadata
            const processedMessage = {
                id: eventData.id || crypto.randomUUID(),
                message: eventData.message || JSON.stringify(eventData),
                timestamp: new Date().toISOString()
            };
            
            processedMessages.push(processedMessage);
            context.log('✨ Message processed:', processedMessage);
            
        } catch (error) {
            context.error(`❌ Error processing message: ${error}`);
        }
    }
    
    // Send processed messages to output Event Hub
    if (processedMessages.length > 0) {
        context.extraOutputs.set(eventHubOutput, processedMessages);
        context.log(`📤 Sent ${processedMessages.length} message(s) to output Event Hub`);
    }
}

app.eventHub('EventHubsTrigger', {
    connection: 'EventHubConnection',
    eventHubName: '%INPUT_EVENTHUB_NAME%',
    cardinality: 'many',
    extraOutputs: [eventHubOutput],
    handler: EventHubsTrigger
});

Pode consultar o projeto modelo completo aqui.

import { app, InvocationContext, output } from "@azure/functions";

interface EventMessage {
    id: string;
    message: string;
    timestamp: string;
}

const eventHubOutput = output.eventHub({
    connection: 'EventHubConnection',
    eventHubName: '%OUTPUT_EVENTHUB_NAME%'
});

export async function EventHubsTrigger(messages: unknown[], context: InvocationContext): Promise<void> {
    context.log(`🔄 Event hub function processing ${messages.length} message(s)`);
    
    const processedMessages: EventMessage[] = [];
    
    for (const message of messages) {
        try {
            // Parse the incoming message
            const eventData = typeof message === 'string' ? JSON.parse(message) : message;
            context.log('📨 Processing event:', eventData);
            
            // Create processed message with additional metadata
            const processedMessage: EventMessage = {
                id: eventData.id || crypto.randomUUID(),
                message: eventData.message || JSON.stringify(eventData),
                timestamp: new Date().toISOString()
            };
            
            processedMessages.push(processedMessage);
            context.log('✨ Message processed:', processedMessage);
            
        } catch (error) {
            context.error(`❌ Error processing message: ${error}`);
        }
    }
    
    // Send processed messages to output Event Hub
    if (processedMessages.length > 0) {
        context.extraOutputs.set(eventHubOutput, processedMessages);
        context.log(`📤 Sent ${processedMessages.length} message(s) to output Event Hub`);
    }
}

app.eventHub('EventHubsTrigger', {
    connection: 'EventHubConnection',
    eventHubName: '%INPUT_EVENTHUB_NAME%',
    cardinality: 'many',
    extraOutputs: [eventHubOutput],
    handler: EventHubsTrigger
});

Pode consultar o projeto modelo completo aqui.

param($InputEvents, $TriggerMetadata)

Write-Host "🔄 Event hub function processing $($InputEvents.Count) message(s)"

$processedMessages = @()

foreach ($message in $InputEvents) {
    try {
        # Parse the incoming message
        $eventData = $message | ConvertFrom-Json -ErrorAction SilentlyContinue
        if (-not $eventData) {
            $eventData = @{ message = $message }
        }

        Write-Host "📨 Processing event: $($eventData | ConvertTo-Json -Compress)"

        # Create processed message with additional metadata
        $processedMessage = @{
            id        = if ($eventData.id) { $eventData.id } else { [guid]::NewGuid().ToString() }
            message   = if ($eventData.message) { $eventData.message } else { ($eventData | ConvertTo-Json -Compress) }
            timestamp = (Get-Date).ToUniversalTime().ToString('o')
        }

        $processedMessages += $processedMessage
        Write-Host "✨ Message processed: $($processedMessage | ConvertTo-Json -Compress)"
    }
    catch {
        Write-Error "❌ Error processing message: $_"
    }
}

# Send processed messages to output Event Hub
if ($processedMessages.Count -gt 0) {
    Push-OutputBinding -Name OutputEvents -Value ($processedMessages | ConvertTo-Json -Compress)
    Write-Host "📤 Sent $($processedMessages.Count) message(s) to output Event Hub"
}

O gatilho está definido no correspondente function.json.

Pode consultar o projeto modelo completo aqui.

import azure.functions as func
import logging
import json
from datetime import datetime, timezone
import random
import uuid
from typing import List

app = func.FunctionApp()

# News article data model
class NewsArticle:
            title=random.choice(titles_templates).format(topic=topic),
            content=f"Comprehensive coverage of the latest developments in {topic}. " * random.randint(10, 20),
            author=random.choice(authors),
            source=random.choice(sources),
            category=random.choice(categories),
            published_date=datetime.now(timezone.utc),
            view_count=random.randint(100, 10000),
            sentiment_score=round(random.uniform(-1.0, 1.0), 2),
            status=random.choice(["Published", "Featured"]),
            tags=[random.choice(topics) for _ in range(random.randint(3, 5))]
        )
        articles.append(article)
    
    # Send articles to Event Hub
    events_json = json.dumps([article.to_dict() for article in articles])
    event.set(events_json)
    
    logging.info(f'✅ HIGH-THROUGHPUT: Successfully generated {num_articles} news articles in ~10 seconds')


# Event Hub trigger - processes news articles
@app.event_hub_message_trigger(arg_name="events", event_hub_name="news",
                                connection="EventHubConnection")
def EventHubsTrigger(events: List[func.EventHubEvent]):
    """Process news articles from Event Hub with sentiment analysis and engagement tracking"""
    
    # Handle both single event and list of events
    if not isinstance(events, list):
        events = [events]
    
    batch_articles = []
    failed_count = 0
    
    for event in events:
        try:
            # Parse the event data
            event_data = json.loads(event.get_body().decode('utf-8'))
            
            # Handle both single article and array of articles
            articles = event_data if isinstance(event_data, list) else [event_data]
            
            for article_data in articles:
                # Process each article
                article_id = article_data.get('ArticleId')
                title = article_data.get('Title')
                author = article_data.get('Author')

Pode consultar o projeto modelo completo aqui.

Depois de verificares a tua função localmente, está na altura de a publicares no Azure.

Publicar no Azure

Este projeto está configurado para usar o azd up comando para implementar o seu código numa nova aplicação de funções num plano Flex Consumption no Azure. Como já provisionaste os recursos, este comando envia o teu código para a aplicação de funções existente.

Sugestão

Este projeto inclui um conjunto de ficheiros Bicep que azd servem para criar uma implementação segura num plano Flex Consumption que segue as melhores práticas.

A partir da pasta raiz do repositório, execute o seguinte comando para implementar o seu projeto de código na aplicação de funções no Azure:

azd deploy

A implementação empacota o seu código e implementa-o na aplicação de funções. Quando o comando termina, vê ligações para os recursos que criou.

Verificar a implementação

Após a implementação terminar, a função de disparo do seu Hub de Eventos começa automaticamente a processar eventos à medida que chegam ao hub de eventos.

  1. No portal Azure, vai à tua nova aplicação de funções.

  2. Selecione Log stream no menu esquerdo para monitorizar as execuções das suas funções em tempo real.

  3. Vês entradas de registo que mostram a tua função de disparo do Event Hubs a processar eventos gerados pelo disparador Timer.

Reimplantar o teu código

Executa o azd up comando tantas vezes quanto precisares tanto para provisionar os teus recursos Azure como para implementar atualizações de código na tua aplicação de funções.

Observação

Os arquivos de código implantados são sempre substituídos pelo pacote de implantação mais recente.

Suas respostas iniciais a azd prompts e quaisquer variáveis de ambiente geradas por azd são armazenadas localmente em seu ambiente nomeado. Use o azd env get-values comando para revisar todas as variáveis em seu ambiente que foram usadas ao criar recursos do Azure.

Limpeza de recursos

Quando terminar de trabalhar com a sua function app e recursos relacionados, use este comando para eliminar a function app e os seus recursos relacionados do Azure e evitar quaisquer custos adicionais:

azd down --no-prompt

Observação

A --no-prompt opção instrui azd a excluir seu grupo de recursos sem uma confirmação sua.

Este comando não afeta seu projeto de código local.