练习 - 生成 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

创建和配置事件中心

对于事件中心,需要指定其应侦听的命名空间。 此外,还需要将授权规则配置为 ListenSend

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 函数并模拟遥测数据。 还可以将 IoT 设备绑定到 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

注释

请使用 functions-version 4,因为 2 和 3 已于 2022 年 12 月停用。

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 文件夹内生成多个文件:

  • 具有预定义 Azure 依赖项的 pom.xml 生成文件。
  • 用于保存本地部署和手动测试的应用程序设置的 local.settings.json 文件。
  • 用于启用 Azure Functions 扩展捆绑包的host.json文件。
  • 包含 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 的类存储此函数使用的数据,你需要实现该类。 在Function.java所在的同一位置创建名为TelemetryItem.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 Functions 时,它们已传输到世界各地! 此外,还可以在 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 云

通过运行 mvn azure-functions:deploy 命令并继续在 Azure 上触发部署。

mvn azure-functions:deploy