Exercício – Processar eventos e armazenar dados no Azure Cosmos DB
Uma segunda função poderá escutar os eventos de um namespace específico no Hub de Eventos do Azure, bem como processá-los e armazená-los em um banco de dados criado com o Azure Cosmos DB.
Criar um banco de dados usando o Azure Cosmos DB
Use o comando az cosmosdb create
para criar um banco de dados. O comando usa uma conta, um banco de dados e um contêiner SQL do Azure Cosmos DB.
az cosmosdb create \
--resource-group $RESOURCE_GROUP \
--name $COSMOS_DB_ACCOUNT
az cosmosdb sql database create \
--resource-group $RESOURCE_GROUP \
--account-name $COSMOS_DB_ACCOUNT \
--name TelemetryDb
az cosmosdb sql container create \
--resource-group $RESOURCE_GROUP \
--account-name $COSMOS_DB_ACCOUNT \
--database-name TelemetryDb \
--name TelemetryInfo \
--partition-key-path '/temperatureStatus'
Para nosso cenário, a temperatura é interessante. Portanto, definiremos temperatureStatus
como uma chave de partição.
Criar, configurar e implantar outra função do Azure
Com os Hubs de Eventos, será possível começar usando fluxos de dados em megabytes e aumentar para gigabytes ou terabytes. O recurso de ampliação automática é uma das várias opções disponíveis para aumentar o número de unidades de produtividade de modo a atender às suas necessidades de uso.
Os aplicativos de consumo de cada função têm uma exibição separada da do fluxo de eventos. Eles leem o fluxo de forma de maneira independente em seu próprio ritmo e com seus próprios deslocamentos.
Para o nosso cenário, você vai criar uma função de consumo do Azure à guisa de exemplo. Para ser criada de acordo com as boas práticas, a função deverá ser independente, com sua própria conta de armazenamento e vinculações para um acoplamento e escalabilidade flexíveis.
az storage account create \
--resource-group $RESOURCE_GROUP \
--name $STORAGE_ACCOUNT"c" \
--sku Standard_LRS
az functionapp create \
--resource-group $RESOURCE_GROUP \
--name $FUNCTION_APP"-c"\
--storage-account $STORAGE_ACCOUNT"c" \
--consumption-plan-location $LOCATION \
--runtime java \
--functions-version 4
Recuperar cadeias de conexão
A função de consumidor precisa obter informações sobre a conta de armazenamento e o hub de eventos. Também precisará estar ciente do banco de dados no qual gravará os eventos processados.
AZURE_WEB_JOBS_STORAGE=$( \
az storage account show-connection-string \
--resource-group $RESOURCE_GROUP \
--name $STORAGE_ACCOUNT"c" \
--query connectionString \
--output tsv)
echo $AZURE_WEB_JOBS_STORAGE
COSMOS_DB_CONNECTION_STRING=$( \
az cosmosdb keys list \
--resource-group $RESOURCE_GROUP \
--name $COSMOS_DB_ACCOUNT \
--type connection-strings \
--query 'connectionStrings[0].connectionString' \
--output tsv)
echo $COSMOS_DB_CONNECTION_STRING
Você pode usar o comando echo $EVENT_HUB_CONNECTION_STRING
para verificar se a variável continua definida corretamente. Caso contrário, execute o seguinte comando novamente:
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
Essas cadeias de conexão precisam ser armazenadas nas configurações de aplicativo da sua conta do Azure Functions.
az functionapp config appsettings set \
--resource-group $RESOURCE_GROUP \
--name $FUNCTION_APP"-c" \
--settings \
AzureWebJobsStorage=$AZURE_WEB_JOBS_STORAGE \
EventHubConnectionString=$EVENT_HUB_CONNECTION_STRING \
CosmosDBConnectionString=$COSMOS_DB_CONNECTION_STRING
Observação
É possível usar uma instância do Azure Key Vault a fim de armazenar e gerenciar cadeias de conexão para ambientes de produção.
Criar o aplicativo de funções
Antes de criar a próxima função, verifique se você está na pasta adequada.
cd ..
mvn archetype:generate --batch-mode \
-DarchetypeGroupId=com.microsoft.azure \
-DarchetypeArtifactId=azure-functions-archetype \
-DappName=$FUNCTION_APP"-c" \
-DresourceGroup=$RESOURCE_GROUP \
-DappRegion=$LOCATION \
-DappServicePlanName=$LOCATION"plan" \
-DgroupId=com.learn \
-DartifactId=telemetry-functions-consumer
O comando cria um aplicativo como o do último exercício. Você deve excluir os arquivos de teste, atualizar o local.settings.file
usando o comando fetch-app-settings
e, a seguir, substituir o arquivo Function.java
existente.
cd telemetry-functions-consumer
rm -r src/test
Atualize as configurações locais para execução e depuração local.
func azure functionapp fetch-app-settings $FUNCTION_APP"-c"
Depois abra o arquivo Function.java
e substitua o conteúdo pelo seguinte código:
package com.learn;
import com.learn.TelemetryItem.status;
import com.microsoft.azure.functions.annotation.FunctionName;
import com.microsoft.azure.functions.ExecutionContext;
import com.microsoft.azure.functions.OutputBinding;
import com.microsoft.azure.functions.annotation.Cardinality;
import com.microsoft.azure.functions.annotation.CosmosDBOutput;
import com.microsoft.azure.functions.annotation.EventHubTrigger;
public class Function {
@FunctionName("processSensorData")
public void processSensorData(
@EventHubTrigger(
name = "msg",
eventHubName = "", // blank because the value is included in the connection string
cardinality = Cardinality.ONE,
connection = "EventHubConnectionString")
TelemetryItem item,
@CosmosDBOutput(
name = "databaseOutput",
databaseName = "TelemetryDb",
collectionName = "TelemetryInfo",
connectionStringSetting = "CosmosDBConnectionString")
OutputBinding<TelemetryItem> document,
final ExecutionContext context) {
context.getLogger().info("Event hub message received: " + item.toString());
if (item.getPressure() > 30) {
item.setNormalPressure(false);
} else {
item.setNormalPressure(true);
}
if (item.getTemperature() < 40) {
item.setTemperatureStatus(status.COOL);
} else if (item.getTemperature() > 90) {
item.setTemperatureStatus(status.HOT);
} else {
item.setTemperatureStatus(status.WARM);
}
document.setValue(item);
}
}
Crie outro arquivo chamado TelemetryItem.java na mesma localização do Function.java e adicione o seguinte código:
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;
}
}
Quando o hub de eventos recebe a mensagem, ele gera um evento. A função processSensorData
é executada quando ela recebe o evento. A seguir, o comando irá processar os dados de eventos e usar uma vinculação de resultados do Azure Cosmos DB para enviar os resultados para o banco de dados. Vamos usar a classe TelemetryItem.java
novamente. Os objetos do TelemetryItem
podem ser considerados como um contrato controlado pelo consumidor entre os participantes desse sistema controlado por evento.
Executar localmente
É possível receber eventos do mundo todo usando o Azure Functions. Sim, é possível receber eventos localmente em seu computador de desenvolvimento!
mvn clean package
mvn azure-functions:run
Após as mensagens de compilação e inicialização, você verá os eventos de recebidos quando a função é executada:
[2021-01-19T16:45:24.709Z] Executing 'Functions.processSensorData' (Reason='(null)', Id=87354afa-abf4-4963-bd44-0c1421048240)
[2021-01-19T16:45:24.712Z] Event hub message received: TelemetryItem={id=null,temperature=21.653044570769897,pressure=36.061288095436126}
[2021-01-19T16:45:24.712Z] Function "processSensorData" (Id: 87354afa-abf4-4963-bd44-0c1421048240) invoked by Java Worker
No portal do Azure, acesse sua conta do Azure Cosmos DB. Selecione Data Explorer e TelemetryInfo. Depois selecione Itens para ver seus dados quando eles chegarem.
Implantar no Azure
Agora, vamos mudar toda a carga de trabalho na nuvem. Para implantar as funções no Azure Functions, você deve usar o comando mvn azure-functions:deploy
do Maven. Verifique se você ainda está no repositório adequado: telemetry-functions.
mvn azure-functions:deploy
Excelente! Implantamos todo o cenário de telemetria enviando os dados a um hub de eventos e consumindo-os usando outra função independente. A função processará os dados e armazenará o resultado em um banco de dados criado com o Azure Cosmos DB. Como podemos garantir que nosso aplicativo esteja atendendo nossos requisitos predefinidos? Usando o monitoramento.