Упражнение. Создание функции Azure для имитации данных телеметрии

Завершено

В нашем примере используется поиск событий. Давайте создадим функцию, которая имитирует данные телеметрии и отправляет их в концентратор событий. Позже другая функция может прослушивать это событие и обрабатывать и хранить его в базе данных, созданной с помощью Azure Cosmos DB.

Визуализация событий для покупки кофе в кафе.

Подготовьте среду

Давайте определим некоторые переменные среды, чтобы обеспечить максимально короткие и понятные команды. Определите заполнители <value> и вставьте и выполните следующие команды в терминале или средстве командной строки:

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>

Заметка

Чтобы задать переменную LOCATION, можно проверить команду az functionapp list-consumption-locations и использовать ближайшее местоположение.

Создание необходимых компонентов

Подготовка ресурсов в Azure занимает некоторое время. Начнем с создания компонента как можно раньше, чтобы избежать длительных ожиданий позже.

Создание группы ресурсов

Всегда рекомендуется привязать все ресурсы обучения, доказательства концепции или прототипа в одной группе ресурсов. Таким образом можно удобно очистить все используемые службы с помощью одной команды. Чтобы создать группу ресурсов в указанном расположении, выполните следующую команду в терминале:

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

Создание и настройка концентратора событий

Для концентратора событий необходимо указать пространство имен, к которому он должен подключаться. Кроме того, необходимо настроить правило авторизации для Listen и 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

Создание, настройка и развертывание функции Azure

Чтобы сделать этот пример максимально реалистичным, создайте функцию Azure и имитируйте данные телеметрики. Вы также можете привязать устройство Интернета вещей к функции Azure, которая будет принимать реальные данные. Поскольку эта функция воспроизводит события, давайте добавим флаг p или -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

Заметка

Используйте функции-версии 4, так как версии 2 и 3 были устаревшими в декабре 2022 года.

Когда команда az functionapp create создает приложение-функцию, он также создает ресурс Application Insights с тем же именем. Мы используем этот ресурс позже для мониторинга.

Чтобы получить строки подключения для учетной записи хранения и концентратора событий, используйте следующие команды, чтобы сохранить их в переменных среды, а затем отобразить их с помощью команды 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

Чтобы сохранить строки подключения в параметрах приложения учетной записи функции Azure, выполните следующую команду в терминале:

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

Теперь центр событий ваших ресурсов Azure и функция Azure созданы и настроены для правильной совместной работы.

Затем создайте проект локальных функций с помощью 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

Эта команда создает несколько файлов в папке telemetry-functions-producer:

  • Файл сборки pom.xml с предопределенными зависимостями Azure.
  • Файл local.settings.json для хранения параметров приложения для локального развертывания и ручного тестирования.
  • Файл host.json, который включает пакет расширений функций Azure.
  • Файл Function.java, включающий функцию триггера HTTP по умолчанию.
  • Несколько тестовых файлов, которые этот модуль Learn не использует.

Мы не касаемся тестовых файлов в этом модуле Learn, поэтому вы можете удалить их.

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

Для локального выполнения параметры приложения должны быть извлечены и сохранены в файле local.settings.json. Это можно сделать автоматически, выполнив команду fetch-app-settings.

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

Затем откройте файл Function.java и замените содержимое следующим кодом:

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

Функция generateSensorData имитирует датчик, который отправляет значения температуры и давления в концентратор событий. Триггер таймера запускает функцию каждые 10 секунд, а выходная привязка концентратора событий отправляет возвращаемое значение в концентратор событий.

Когда концентратор событий получает сообщение, он создает событие.

Данные, используемые этой функцией, хранятся с помощью класса TelemetryItem, который необходимо реализовать. Создайте новый файл с именем TelemetryItem.java в том же расположении, что и Function.java, и добавьте следующий код:

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

Запуск локально

При локальном запуске функций Azure они уже передаются по всему миру! Кроме того, их можно просмотреть на портале Azure.

mvn clean package
mvn azure-functions:run

После некоторых сообщений сборки и запуска вы увидите выходные данные, аналогичные следующему примеру при каждом запуске функций:

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

Заметка

Перед развертыванием и запуском функции в облаке Azure можно отправлять события с локального компьютера по всему миру! Это очень полезно для разработки, отладки и локального тестирования.

Развертывание в Azure

Активируйте развертывание в Azure, выполнив команду mvn azure-functions:deploy и продолжайте работу.

mvn azure-functions:deploy