Guida introduttiva: Elaborare eventi in tempo reale usando Funzioni di Azure

In questo articolo si usa Azure Developer CLI (azd) per creare una funzione trigger di Hub eventi per l'elaborazione di eventi in tempo reale nelle Funzioni di Azure. Dopo aver verificato il codice in locale, lo distribuisci in una nuova app di funzioni serverless in esecuzione su un piano Flex Consumption di Azure.

L'origine del progetto usa azd per creare l'app per le funzioni e le risorse correlate e per distribuire il codice in Azure. Questa distribuzione segue le procedure consigliate correnti per distribuzioni di Funzioni di Azure sicure e scalabili.

Per impostazione predefinita, il piano Flex Consumption segue un modello di fatturazione con pagamento in base al consumo, il che significa che è possibile completare questo articolo e sostenere solo un costo ridotto di pochi centesimi di USD o inferiore nell'account Azure.

Questo articolo supporta la versione 4 del modello di programmazione Node.js per Funzioni di Azure.

Questo articolo supporta la versione 2 del modello di programmazione Python per Funzioni di Azure.

Prerequisiti

Inizializzare il progetto

Usare il azd init comando per creare un progetto di codice di Funzioni di Azure locale da un modello.

Nel terminale locale o nel prompt dei comandi eseguire questo comando azd init in una cartella vuota:

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

Questo comando esegue il pull dei file di progetto dal repository template e inizializza il progetto nella cartella corrente. Il flag -e imposta un nome per l'ambiente corrente. In azdl'ambiente mantiene un contesto di distribuzione univoco per l'app ed è possibile definire più di uno. Il nome dell'ambiente viene usato anche nel nome del gruppo di risorse creato in Azure.

Nel terminale locale o nel prompt dei comandi eseguire questo comando azd init in una cartella vuota:

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

Questo comando esegue il pull dei file di progetto dal repository template e inizializza il progetto nella cartella corrente. Il flag -e imposta un nome per l'ambiente corrente. In azdl'ambiente mantiene un contesto di distribuzione univoco per l'app ed è possibile definire più di uno. Il nome dell'ambiente viene usato anche nel nome del gruppo di risorse creato in Azure.

Nel terminale locale o nel prompt dei comandi eseguire questo comando azd init in una cartella vuota:

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

Questo comando esegue il pull dei file di progetto dal repository template e inizializza il progetto nella cartella corrente. Il flag -e imposta un nome per l'ambiente corrente. In azdl'ambiente mantiene un contesto di distribuzione univoco per l'app ed è possibile definire più di uno. Il nome dell'ambiente viene usato anche nel nome del gruppo di risorse creato in Azure.

Creare e attivare un ambiente virtuale

Nella cartella principale, eseguire questi comandi per creare e attivare un ambiente virtuale denominato .venv:

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

Se Python non installa il pacchetto venv nella distribuzione Linux, eseguire il comando seguente:

sudo apt-get install python3-venv

Nel terminale locale o nel prompt dei comandi eseguire questo comando azd init in una cartella vuota:

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

Questo comando esegue il pull dei file di progetto dal repository template e inizializza il progetto nella cartella corrente. Il flag -e imposta un nome per l'ambiente corrente. In azdl'ambiente mantiene un contesto di distribuzione univoco per l'app ed è possibile definire più di uno. Il nome dell'ambiente viene usato anche nel nome del gruppo di risorse creato in Azure.

Nel terminale locale o nel prompt dei comandi eseguire questo comando azd init in una cartella vuota:

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

Questo comando esegue il pull dei file di progetto dal repository template e inizializza il progetto nella cartella corrente. Il flag -e imposta un nome per l'ambiente corrente. In azdl'ambiente mantiene un contesto di distribuzione univoco per l'app ed è possibile definire più di uno. Il nome dell'ambiente viene usato anche nel nome del gruppo di risorse creato in Azure.

Nel terminale locale o nel prompt dei comandi eseguire questo comando azd init in una cartella vuota:

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

Questo comando esegue il pull dei file di progetto dal repository template e inizializza il progetto nella cartella corrente. Il flag -e imposta un nome per l'ambiente corrente. In azdl'ambiente mantiene un contesto di distribuzione univoco per l'app ed è possibile definire più di uno. Il nome dell'ambiente viene usato anche nel nome del gruppo di risorse creato in Azure.

Creare risorse di Azure

Prima di poter eseguire localmente la funzione, è necessario creare un namespace e un hub Event Hubs in Azure. Usare azd provision per creare queste risorse e configurare le impostazioni locali aggiungendo il file dilocal.settings.json necessario.

  1. Eseguire questo comando per accedere ad Azure:

    azd auth login
    

    Seguire le istruzioni per eseguire l'autenticazione usando l'account Azure.

  2. Dalla cartella radice eseguire il comando seguente per creare le risorse di Azure:

    azd provision
    
  3. Quando richiesto, specificare questi parametri di distribuzione obbligatori:

    Parametro Descrizione
    Sottoscrizione di Azure Sottoscrizione in cui crei le tue risorse.
    Località di Azure area di Azure in cui creare il gruppo di risorse che contiene le nuove risorse di Azure. Vengono visualizzate solo le aree che attualmente supportano il piano a consumo Flex.
    vnetEnabled Usare un valore di False per evitare il sovraccarico aggiuntivo della creazione di risorse di rete virtuale.

    Il azd provision comando crea le risorse di Azure necessarie, tra cui uno spazio dei nomi e un hub di Hub eventi, un'app per le funzioni Flex Consumption, Application Insights e un account di archiviazione. Configura anche il file local.settings.json con le informazioni di connessione di Event Hubs.

Eseguire l'ambiente locale

  1. In una finestra del terminale separata avviare l'emulatore di archiviazione Azurite:

    azurite
    

    Il processo host locale delle Funzioni usa l'emulatore Azurite per la connessione di archiviazione interna (AzureWebJobsStorage) richiesta dal runtime.

  1. Per avviare l'app per le funzioni, eseguire questi comandi in un terminale o nel prompt dei comandi per passare alla cartella del src progetto e avviare l'app per le funzioni:

    cd src
    func start
    
  1. Per avviare l'app per le funzioni, eseguire questo comando in un terminale o nel prompt dei comandi:

    func start
    
  1. Per compilare e avviare l'app per le funzioni, eseguire questi comandi in un terminale o nel prompt dei comandi:

    mvn clean package
    mvn azure-functions:run
    
  1. Per installare le dipendenze e avviare l'app per le funzioni, eseguire questi comandi in un terminale o nel prompt dei comandi:

    npm install
    npm start  
    
  1. Per installare le dipendenze e avviare l'app per le funzioni, eseguire questi comandi in un terminale o nel prompt dei comandi:

    cd src
    npm install
    npm start  
    
  1. Per avviare l'app per le funzioni, eseguire questo comando in un terminale o nel prompt dei comandi:

    func start
    
  1. Se richiesto, consentire la chiamata di Core Tools (func.exe) tramite il firewall.

  2. Quando l'host delle funzioni viene avviato nella cartella del progetto locale, visualizza sul terminale le informazioni relative alle funzioni.

    Questo esempio include una funzione trigger timer che genera automaticamente articoli di notizie ogni 10 secondi e li invia a Hub eventi. La funzione trigger di Hub eventi elabora quindi questi eventi ed esegue l'analisi del sentiment e il rilevamento dell'engagement.

    L'output è simile a questo esempio:

     [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. Al termine, premere CTRL+C nella finestra del terminale per arrestare il processo host func.exe.

  4. Chiudere la finestra in cui è in esecuzione Azurite.

  1. Eseguire deactivate per arrestare l'ambiente virtuale.

Esaminare il codice (facoltativo)

È possibile esaminare il codice che definisce la funzione trigger di Hub eventi:

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}");

È possibile esaminare il progetto modello completo here.

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()));
        }
    }
}

È possibile esaminare il progetto modello completo here.

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
});

È possibile esaminare il progetto modello completo here.

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
});

È possibile esaminare il progetto modello completo here.

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"
}

Il trigger viene definito nel function.json corrispondente.

È possibile esaminare il progetto modello completo here.

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')

È possibile esaminare il progetto modello completo here.

Dopo aver verificato la funzione in locale, è possibile pubblicarla in Azure.

Distribuzione su Azure

Questo progetto è configurato per l'uso del comando azd up al fine di distribuire il codice in una nuova app per le funzioni in un piano a consumo flessibile in Azure. Poiché è già stato effettuato il provisioning delle risorse, questo comando distribuisce il codice nell'app esistente per le funzioni.

Suggerimento

Questo progetto include un set di file Bicep che azd usa per creare una distribuzione sicura in un piano a consumo Flex che segue le procedure consigliate.

Dalla cartella radice del repository eseguire il comando seguente per distribuire il progetto di codice nell'app per le funzioni in Azure:

azd deploy

Il processo di distribuzione crea un pacchetto con il codice e lo distribuisce nell'applicazione per le funzioni. Al termine del comando, vengono visualizzati collegamenti alle risorse create.

Verificare la distribuzione

Al termine della distribuzione, la funzione trigger di Event Hub avvia automaticamente l'elaborazione degli eventi al loro arrivo nell'Hub eventi.

  1. Nel portale di Azure passare alla nuova app per le funzioni.

  2. Selezionare Log stream (Flusso di log ) dal menu a sinistra per monitorare le esecuzioni delle funzioni in tempo reale.

  3. Vengono visualizzate voci di log che indicano che la funzione di trigger di Event Hubs sta elaborando gli eventi generati dal trigger Timer.

Ridistribuire il codice

Eseguire il comando azd up quante volte è necessario per effettuare il provisioning delle risorse di Azure e distribuire gli aggiornamenti del codice nell'app per le funzioni.

Annotazioni

I file di codice distribuiti vengono sempre sovrascritti dal pacchetto di distribuzione più recente.

Le risposte iniziali alle richieste di azd e a tutte le variabili di ambiente generate da azd, vengono archiviate localmente nell'ambiente denominato. Usare il comando azd env get-values per esaminare tutte le variabili nell'ambiente usato durante la creazione di risorse di Azure.

Pulire le risorse

Al termine dell'uso dell'app per le funzioni e delle risorse correlate, usare questo comando per eliminare l'app per le funzioni e le relative risorse da Azure ed evitare di sostenere ulteriori costi:

azd down --no-prompt

Annotazioni

L'opzione --no-prompt indica a azd di eliminare il gruppo di risorse senza conferma.

Questo comando non influisce sul progetto di codice locale.