Esercizio: Creare una funzione di Azure per simulare i dati di telemetria

Completato

Per questo esempio viene usata l'origine degli eventi. Verrà ora creata una funzione che simula i dati di telemetria e li invia a un hub eventi. Successivamente, un'altra funzione può restare in ascolto di questo evento ed elaborarlo e archiviarlo in un database creato con Azure Cosmos DB.

Visualization of event sourcing for buying coffee at a coffee shop.

Predisporre l'ambiente

Definire alcune variabili di ambiente per fare in modo che i comandi seguenti siano il più possibile brevi e comprensibili. Definire i segnaposto <value> e incollare ed eseguire i comandi seguenti nel terminale o nello strumento da riga di comando:

RESOURCE_GROUP=<value>
EVENT_HUB_NAMESPACE=<value>
EVENT_HUB_NAME=<value>
EVENT_HUB_AUTHORIZATION_RULE=<value>
COSMOS_DB_ACCOUNT=<value>
STORAGE_ACCOUNT=<value>
FUNCTION_APP=<value>
LOCATION=<value>

Nota

Per impostare la variabile LOCATION, è possibile controllare il comando az functionapp list-consumption-locations e usare la posizione più vicina.

Creare i componenti richiesti

Il provisioning delle risorse in Azure richiede un certo tempo. Si inizierà subito con la creazione dei componenti per evitare lunghe attese in un secondo momento.

Creare un gruppo di risorse

È sempre consigliabile associare tutte le risorse di un training, un modello di verifica o un prototipo in un unico gruppo di risorse. In questo modo è possibile pulire agevolmente tutti i servizi usati con un solo comando. Per creare un gruppo di risorse nel percorso specificato, eseguire il comando seguente nel terminale:

az group create \
    --name $RESOURCE_GROUP \
    --location $LOCATION

Creare e configurare un hub eventi

Per l'hub eventi è necessario specificare lo spazio dei nomi per cui deve essere in ascolto. Inoltre, è necessario configurare la regola di autorizzazione per Listen e Send.

az eventhubs namespace create \
    --resource-group $RESOURCE_GROUP \
    --name $EVENT_HUB_NAMESPACE
az eventhubs eventhub create \
    --resource-group $RESOURCE_GROUP \
    --name $EVENT_HUB_NAME \
    --namespace-name $EVENT_HUB_NAMESPACE \
az eventhubs eventhub authorization-rule create \
    --resource-group $RESOURCE_GROUP \
    --name $EVENT_HUB_AUTHORIZATION_RULE \
    --eventhub-name $EVENT_HUB_NAME \
    --namespace-name $EVENT_HUB_NAMESPACE \
    --rights Listen Send

Compilare, configurare e distribuire la funzione di Azure

Per rendere questo esempio il più realistico possibile, creare una funzione di Azure e simulare i dati di telemetria. È anche possibile associare un dispositivo IoT alla funzione di Azure, che quindi accetterà dati reali. Poiché questa funzione è quella che produce eventi, aggiungere un flag p o -p.

az storage account create \
    --resource-group $RESOURCE_GROUP \
    --name $STORAGE_ACCOUNT"p" \
    --sku Standard_LRS
az functionapp create \
    --resource-group $RESOURCE_GROUP \
    --name $FUNCTION_APP"-p"\
    --storage-account $STORAGE_ACCOUNT"p" \
    --consumption-plan-location $LOCATION \
    --runtime java \
    --functions-version 4

Nota

Usare la versione 4 delle funzioni, poiché le versioni 2 e 3 sono state deprecate nel mese di dicembre 2022.

Quando il comando az functionapp create crea l'app per le funzioni, crea anche una risorsa di Application Insights con lo stesso nome. Questa risorsa verrà usata in seguito per il monitoraggio.

Per recuperare le stringhe di connessione per l'account di archiviazione e l'hub eventi, usare i comandi seguenti per salvarle nelle variabili di ambiente e quindi visualizzarle con il comando echo.

AZURE_WEB_JOBS_STORAGE=$( \
    az storage account show-connection-string \
        --resource-group $RESOURCE_GROUP \
        --name $STORAGE_ACCOUNT"p" \
        --query connectionString \
        --output tsv)
echo $AZURE_WEB_JOBS_STORAGE
EVENT_HUB_CONNECTION_STRING=$( \
    az eventhubs eventhub authorization-rule keys list \
        --resource-group $RESOURCE_GROUP \
        --name $EVENT_HUB_AUTHORIZATION_RULE \
        --eventhub-name $EVENT_HUB_NAME \
        --namespace-name $EVENT_HUB_NAMESPACE \
        --query primaryConnectionString \
        --output tsv)
echo $EVENT_HUB_CONNECTION_STRING

Per archiviare le stringhe di connessione nelle impostazioni dell'applicazione dell'account Funzioni di Azure, eseguire il comando seguente nel terminale:

az functionapp config appsettings set \
    --resource-group $RESOURCE_GROUP \
    --name $FUNCTION_APP"-p" \
    --settings \
        AzureWebJobsStorage=$AZURE_WEB_JOBS_STORAGE \
        EventHubConnectionString=$EVENT_HUB_CONNECTION_STRING

Vengono ora creati e configurati l'hub eventi e la funzione di Azure per le risorse di Azure in modo da funzionare correttamente insieme.

Ora creare un progetto di funzioni locali con Maven.

mvn archetype:generate --batch-mode \
    -DarchetypeGroupId=com.microsoft.azure \
    -DarchetypeArtifactId=azure-functions-archetype \
    -DappName=$FUNCTION_APP"-p" \
    -DresourceGroup=$RESOURCE_GROUP \
    -DappRegion=$LOCATION \
    -DappServicePlanName=$LOCATION"plan" \
    -DgroupId=com.learn \
    -DartifactId=telemetry-functions-producer

Questo comando genera diversi file all'interno di una cartella telemetry-functions-producer:

  • Il file di compilazione pom.xml con dipendenze di Azure predefinite.
  • Il file local.settings.json in cui archiviare le impostazioni dell'applicazione per la distribuzione locale e i test manuali.
  • Un file host.json che abilita il bundle estensione di Funzioni di Azure.
  • Un file Function.java che include la funzione di trigger HTTP predefinita.
  • Alcuni file di test non usati da questo modulo Learn.

I file di test di questo modulo Learn non vengono usati, quindi si possono eliminare.

cd telemetry-functions-producer
rm -r src/test

Per l'esecuzione locale, le impostazioni dell'applicazione devono essere recuperate e archiviate nel file local.settings.json. L'operazione può essere eseguita automaticamente usando il comando fetch-app-settings.

func azure functionapp fetch-app-settings $FUNCTION_APP"-p"

Successivamente, aprire il file Function.java e sostituirne il contenuto con il codice seguente:

package com.learn;

import com.microsoft.azure.functions.annotation.EventHubOutput;
import com.microsoft.azure.functions.annotation.FunctionName;
import com.microsoft.azure.functions.annotation.TimerTrigger;
import com.microsoft.azure.functions.ExecutionContext;
public class Function {

    @FunctionName("generateSensorData")
    @EventHubOutput(
        name = "event",
        eventHubName = "", // blank because the value is included in the connection string
        connection = "EventHubConnectionString")
    public TelemetryItem generateSensorData(
        @TimerTrigger(
            name = "timerInfo",
            schedule = "*/10 * * * * *") // every 10 seconds
            String timerInfo,
        final ExecutionContext context) {
            context.getLogger().info("Java Timer trigger function executed at: " + java.time.LocalDateTime.now());
            double temperature = Math.random() * 100;
            double pressure = Math.random() * 50;
        return new TelemetryItem(temperature, pressure);
    }
}

La funzione generateSensorData simula un sensore che invia le letture di temperatura e pressione all'hub eventi. Un trigger timer esegue la funzione ogni 10 secondi e un binding di output dell'hub eventi invia il valore restituito all'hub eventi.

Quando l'hub eventi riceve il messaggio, genera un evento.

I dati usati da questa funzione vengono archiviati usando una classe denominata TelemetryItem, che è necessario implementare. Creare un nuovo file denominato TelemetryItem.java nello stesso percorso di Function.java e aggiungere il codice seguente:

package com.learn;

public class TelemetryItem {

    private String id;
    private double temperature;
    private double pressure;
    private boolean isNormalPressure;
    private status temperatureStatus;
    static enum status {
        COOL,
        WARM,
        HOT
    }

    public TelemetryItem(double temperature, double pressure) {
        this.temperature = temperature;
        this.pressure = pressure;
    }

    public String getId() {
        return id;
    }

    public double getTemperature() {
        return temperature;
    }

    public double getPressure() {
        return pressure;
    }

    @Override
    public String toString() {
        return "TelemetryItem={id=" + id + ",temperature="
            + temperature + ",pressure=" + pressure + "}";
    }

    public boolean isNormalPressure() {
        return isNormalPressure;
    }

    public void setNormalPressure(boolean isNormal) {
        this.isNormalPressure = isNormal;
    }

    public status getTemperatureStatus() {
        return temperatureStatus;
    }

    public void setTemperatureStatus(status temperatureStatus) {
        this.temperatureStatus = temperatureStatus;
    }
}

Eseguire localmente

Quando si eseguono funzioni di Azure in locale, vengono già trasmesse in streaming in tutto il mondo. È anche possibile esaminarle nel portale di Azure.

mvn clean package
mvn azure-functions:run

Dopo alcuni messaggi di creazione e avvio, verrà visualizzato un output simile all'esempio seguente per ogni esecuzione delle funzioni:

[2021-01-19T16:25:40.005Z] Executing 'Functions.generateSensorData' (Reason='Timer fired at 2021-01-19T17:25:40.0044630+01:00', Id=fcf567a3-03ec-4159-9714-aa4449861b30)
[2021-01-19T16:25:40.011Z] Java Timer trigger function executed at: 2021-01-19T17:25:40.009405
[2021-01-19T16:25:40.013Z] Function "generateSensorData" (Id: fcf567a3-03ec-4159-9714-aa4449861b30) invoked by Java Worker
[2021-01-19T16:25:40.048Z] Executed 'Functions.generateSensorData' (Succeeded, Id=fcf567a3-03ec-4159-9714-aa4449861b30, Duration=43ms)

Nota

Prima di distribuire ed eseguire la funzione nel cloud di Azure, è possibile inviare gli eventi dal computer locale in tutto il mondo. Questo è molto utile per lo sviluppo, il debug e i test locali.

Distribuisci in Azure

Attivare la distribuzione in Azure eseguendo il comando mvn azure-functions:deploy e continuare.

mvn azure-functions:deploy