Выходная привязка Сетки событий Azure для функций Azure

Используйте выходную привязку Сетки событий для записи событий в пользовательский раздел. Необходимо иметь допустимый ключ доступа для пользовательского раздела. Выходная привязка Сетки событий не поддерживает подписанные URL-адреса (маркеры SAS).

Подробные сведения о настройке и конфигурации см. в статье Работа с триггерами и привязками сетки событий в службе Функции Azure.

Внимание

В этой статье используются вкладки для поддержки нескольких версий модели программирования Node.js. Модель версии 4 общедоступна и предназначена для более гибкого и интуитивно понятного интерфейса для разработчиков JavaScript и TypeScript. Дополнительные сведения о том, как работает модель версии 4, см. в руководстве разработчика по Функции Azure Node.js. Дополнительные сведения о различиях между версиями 3 и 4 см. в руководстве по миграции.

Функции Azure поддерживает две модели программирования для Python. Способ определения привязок зависит от выбранной модели программирования.

Модель программирования Python версии 2 позволяет определять привязки с помощью декораторов непосредственно в коде функции Python. Дополнительные сведения см. в руководстве разработчика Python.

Эта статья поддерживает обе модели программирования.

Внимание

Выходная привязка Сетки событий доступна только для функций 2.x и более поздних версий.

Пример

Тип выходного параметра, используемого с выходной привязкой Сетки событий, зависит от версии среды выполнения Функций, версии расширения привязки и модальности функции C#. Функцию C# можно создать с помощью одного из следующих режимов C#:

В следующем примере показано, как пользовательский тип используется в триггере и в выходной привязке сетки событий:

using System;
using System.Collections.Generic;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;

namespace SampleApp
{
    public static class EventGridFunction
    {
        [Function(nameof(EventGridFunction))]
        [EventGridOutput(TopicEndpointUri = "MyEventGridTopicUriSetting", TopicKeySetting = "MyEventGridTopicKeySetting")]
        public static MyEventType Run([EventGridTrigger] MyEventType input, FunctionContext context)
        {
            var logger = context.GetLogger(nameof(EventGridFunction));

            logger.LogInformation(input.Data.ToString());

            var outputEvent = new MyEventType()
            {
                Id = "unique-id",
                Subject = "abc-subject",
                Data = new Dictionary<string, object>
                {
                    { "myKey", "myValue" }
                }
            };

            return outputEvent;
        }
    }

    public class MyEventType
    {
        public string Id { get; set; }

        public string Topic { get; set; }

        public string Subject { get; set; }

        public string EventType { get; set; }

        public DateTime EventTime { get; set; }

        public IDictionary<string, object> Data { get; set; }
    }
}

В следующем примере показана функция Java, которая записывает сообщение в пользовательский раздел Сетки событий. Для вывода строки эта функция использует метод привязки setValue.

public class Function {
    @FunctionName("EventGridTriggerTest")
    public void run(@EventGridTrigger(name = "event") String content,
            @EventGridOutput(name = "outputEvent", topicEndpointUri = "MyEventGridTopicUriSetting", topicKeySetting = "MyEventGridTopicKeySetting") OutputBinding<String> outputEvent,
            final ExecutionContext context) {
        context.getLogger().info("Java EventGrid trigger processed a request." + content);
        final String eventGridOutputDocument = "{\"id\": \"1807\", \"eventType\": \"recordInserted\", \"subject\": \"myapp/cars/java\", \"eventTime\":\"2017-08-10T21:03:07+00:00\", \"data\": {\"make\": \"Ducati\",\"model\": \"Monster\"}, \"dataVersion\": \"1.0\"}";
        outputEvent.setValue(eventGridOutputDocument);
    }
}

Можно также использовать класс POJO для отправки сообщений Сетки событий.

public class Function {
    @FunctionName("EventGridTriggerTest")
    public void run(@EventGridTrigger(name = "event") String content,
            @EventGridOutput(name = "outputEvent", topicEndpointUri = "MyEventGridTopicUriSetting", topicKeySetting = "MyEventGridTopicKeySetting") OutputBinding<EventGridEvent> outputEvent,
            final ExecutionContext context) {
        context.getLogger().info("Java EventGrid trigger processed a request." + content);

        final EventGridEvent eventGridOutputDocument = new EventGridEvent();
        eventGridOutputDocument.setId("1807");
        eventGridOutputDocument.setEventType("recordInserted");
        eventGridOutputDocument.setEventTime("2017-08-10T21:03:07+00:00");
        eventGridOutputDocument.setDataVersion("1.0");
        eventGridOutputDocument.setSubject("myapp/cars/java");
        eventGridOutputDocument.setData("{\"make\": \"Ducati\",\"model\":\"monster\"");

        outputEvent.setValue(eventGridOutputDocument);
    }
}

class EventGridEvent {
    private String id;
    private String eventType;
    private String subject;
    private String eventTime;
    private String dataVersion;
    private String data;

    public String getId() {
        return id;
    }

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }

    public String getDataVersion() {
        return dataVersion;
    }

    public void setDataVersion(String dataVersion) {
        this.dataVersion = dataVersion;
    }

    public String getEventTime() {
        return eventTime;
    }

    public void setEventTime(String eventTime) {
        this.eventTime = eventTime;
    }

    public String getSubject() {
        return subject;
    }

    public void setSubject(String subject) {
        this.subject = subject;
    }

    public String getEventType() {
        return eventType;
    }

    public void setEventType(String eventType) {
        this.eventType = eventType;
    }

    public void setId(String id) {
        this.id = id;
    }  
}

В следующем примере показана функция TypeScript таймера, которая выводит одно событие:

import { app, EventGridPartialEvent, InvocationContext, output, Timer } from '@azure/functions';

export async function timerTrigger1(myTimer: Timer, context: InvocationContext): Promise<EventGridPartialEvent> {
    const timeStamp = new Date().toISOString();
    return {
        id: 'message-id',
        subject: 'subject-name',
        dataVersion: '1.0',
        eventType: 'event-type',
        data: {
            name: 'John Henry',
        },
        eventTime: timeStamp,
    };
}

app.timer('timerTrigger1', {
    schedule: '0 */5 * * * *',
    return: output.eventGrid({
        topicEndpointUri: 'MyEventGridTopicUriSetting',
        topicKeySetting: 'MyEventGridTopicKeySetting',
    }),
    handler: timerTrigger1,
});

Чтобы вывести несколько событий, верните массив вместо одного объекта. Например:

const timeStamp = new Date().toISOString();
return [
    {
        id: 'message-id',
        subject: 'subject-name',
        dataVersion: '1.0',
        eventType: 'event-type',
        data: {
            name: 'John Henry',
        },
        eventTime: timeStamp,
    },
    {
        id: 'message-id-2',
        subject: 'subject-name',
        dataVersion: '1.0',
        eventType: 'event-type',
        data: {
            name: 'John Doe',
        },
        eventTime: timeStamp,
    },
];

В следующем примере показана функция JavaScript таймера, которая выводит одно событие:

const { app, output } = require('@azure/functions');

const eventGridOutput = output.eventGrid({
    topicEndpointUri: 'MyEventGridTopicUriSetting',
    topicKeySetting: 'MyEventGridTopicKeySetting',
});

app.timer('timerTrigger1', {
    schedule: '0 */5 * * * *',
    return: eventGridOutput,
    handler: (myTimer, context) => {
        const timeStamp = new Date().toISOString();
        return {
            id: 'message-id',
            subject: 'subject-name',
            dataVersion: '1.0',
            eventType: 'event-type',
            data: {
                name: 'John Henry',
            },
            eventTime: timeStamp,
        };
    },
});

Чтобы вывести несколько событий, верните массив вместо одного объекта. Например:

const timeStamp = new Date().toISOString();
return [
    {
        id: 'message-id',
        subject: 'subject-name',
        dataVersion: '1.0',
        eventType: 'event-type',
        data: {
            name: 'John Henry',
        },
        eventTime: timeStamp,
    },
    {
        id: 'message-id-2',
        subject: 'subject-name',
        dataVersion: '1.0',
        eventType: 'event-type',
        data: {
            name: 'John Doe',
        },
        eventTime: timeStamp,
    },
];

В следующем примере показано, как настроить функцию для вывода сообщения о событии Сетки событий. В разделе, где для type задано значение eventGrid, настраиваются значения, необходимые для создания выходной привязки Сетки событий.

{
  "bindings": [
    {
      "type": "eventGrid",
      "name": "outputEvent",
      "topicEndpointUri": "MyEventGridTopicUriSetting",
      "topicKeySetting": "MyEventGridTopicKeySetting",
      "direction": "out"
    },
    {
      "authLevel": "anonymous",
      "type": "httpTrigger",
      "direction": "in",
      "name": "Request",
      "methods": [
        "get",
        "post"
      ]
    },
    {
      "type": "http",
      "direction": "out",
      "name": "Response"
    }
  ]
}

В функции используйте Push-OutputBinding для отправки события в пользовательский раздел через выходную привязку Сетки событий.

using namespace System.Net

# Input bindings are passed in via param block.
param($Request, $TriggerMetadata)

# Write to the Azure Functions log stream.
Write-Host "PowerShell HTTP trigger function processed a request."

# Interact with query parameters or the body of the request.
$message = $Request.Query.Message

Push-OutputBinding -Name outputEvent -Value  @{
    id = "1"
    eventType = "testEvent"
    subject = "testapp/testPublish"
    eventTime = "2020-08-27T21:03:07+00:00"
    data = @{
        Message = $message
    }
    dataVersion = "1.0"
}

Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
    StatusCode = 200
    Body = "OK"
})

В следующем примере показана привязка триггера и функция Python, использующая привязку. Затем событие отправляется в пользовательский раздел, как указано в topicEndpointUri. Пример зависит от того, используется ли модель программирования Python версии 1 или версии 2.

Ниже приведена функция в файле function_app.py:

import logging
import azure.functions as func
import datetime

app = func.FunctionApp()

@app.function_name(name="eventgrid_output")
@app.event_grid_trigger(arg_name="eventGridEvent")
@app.event_grid_output(
    arg_name="outputEvent",
    topic_endpoint_uri="MyEventGridTopicUriSetting",
    topic_key_setting="MyEventGridTopicKeySetting")
def eventgrid_output(eventGridEvent: func.EventGridEvent, 
         outputEvent: func.Out[func.EventGridOutputEvent]) -> None:

    logging.log("eventGridEvent: ", eventGridEvent)

    outputEvent.set(
        func.EventGridOutputEvent(
            id="test-id",
            data={"tag1": "value1", "tag2": "value2"},
            subject="test-subject",
            event_type="test-event-1",
            event_time=datetime.datetime.utcnow(),
            data_version="1.0"))

Атрибуты

Библиотеки C# в процессе и изолированном рабочем процессе используют атрибут для настройки привязки. Вместо этого скрипт C# использует файл конфигурации function.json, как описано в руководстве по скриптам C#.

Конструктор атрибута принимает имя параметра приложения, содержащего имя настраиваемого раздела, и имя параметра приложения, содержащего ключ раздела.

В следующей таблице описаны параметры для EventGridOutputAttribute.

Параметр Описание
TopicEndpointUri Имя параметра приложения, содержащего URI для пользовательского раздела, например MyTopicEndpointUri.
TopicKeySetting Имя параметра приложения, содержащего ключ доступа для пользовательского раздела.
Подключение* Значение общего префикса для параметра, содержащего универсальный код ресурса (URI) конечной точки раздела. Дополнительные сведения о формате именования этого параметра приложения см. в разделе аутентификации на основе удостоверений.

Заметки

В классах Java используйте атрибут EventGridAttribute.

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

public class Function {
    @FunctionName("EventGridTriggerTest")
    public void run(@EventGridTrigger(name = "event") String content,
            @EventGridOutput(name = "outputEvent", topicEndpointUri = "MyEventGridTopicUriSetting", topicKeySetting = "MyEventGridTopicKeySetting") OutputBinding<String> outputEvent, final ExecutionContext context) {
            ...
    }
}

Настройка

В следующей таблице описываются свойства, которые можно задать для options объекта, переданного методу output.eventGrid() .

Свойство Description
topicEndpointUri Имя параметра приложения, содержащего URI для пользовательского раздела, например MyTopicEndpointUri.
topicKeySetting Имя параметра приложения, содержащего ключ доступа для пользовательского раздела.
Подключение* Значение общего префикса для параметра, содержащего универсальный код ресурса (URI) конечной точки раздела. При задании connection свойства topicEndpointUri не следует задавать свойства и topicKeySetting свойства. Дополнительные сведения о формате именования этого параметра приложения см. в разделе аутентификации на основе удостоверений.

Настройка

В следующей таблице описываются свойства конфигурации привязки, которые задаются в файле function.json.

Свойство в function.json Описание
type Должен иметь значениеeventGrid.
direction Должен иметь значениеout. Этот параметр задается автоматически при создании привязки на портале Azure.
name Имя переменной, используемое в коде функции, которая представляет событие.
topicEndpointUri Имя параметра приложения, содержащего URI для пользовательского раздела, например MyTopicEndpointUri.
topicKeySetting Имя параметра приложения, содержащего ключ доступа для пользовательского раздела.
Подключение* Значение общего префикса для параметра, содержащего универсальный код ресурса (URI) конечной точки раздела. Дополнительные сведения о формате именования этого параметра приложения см. в разделе аутентификации на основе удостоверений.

*Для поддержки подключений на основе удостоверений требуется версия 3.3.x или более поздней версии расширения.

Если разработка ведется на локальном компьютере, добавьте параметры приложения в файл local.settings.json в коллекции Values.

Внимание

Убедитесь, что вы задаете значение TopicEndpointUri имени параметра приложения, содержащего URI настраиваемого раздела. Не указывайте URI пользовательского раздела непосредственно в этом свойстве. То же самое применяется при использовании Connection.

Подробные примеры см. в разделе Примеры.

Использование

Тип параметра, поддерживаемый выходной привязкой сетки событий, зависит от версии среды выполнения Функций, версии пакета расширения и используемой модальности C#.

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

Тип Описание
string Событие в виде строки.
byte[] Байт сообщения о событии.
Сериализуемые в JSON типы Объект, представляющий событие JSON. Функции пытаются сериализовать обычный тип объекта CLR (POCO) в данные JSON.

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

Тип Описание
T[] где T является одним из отдельных типов событий Массив, содержащий несколько событий. Каждая запись представляет одно событие.

Для других сценариев вывода создайте и используйте типы из Azure.Messaging.EventGrid напрямую.

Для отправки отдельных сообщений вызывайте параметр метода, например out EventGridOutput paramName, а для записи нескольких сообщений используйте ICollector<EventGridOutput>.

Доступ к выходному сообщению, возвращая значение напрямую или используя context.extraOutputs.set().

Получите доступ к выходному событию с помощью командлета Push-OutputBinding, чтобы отправить событие в выходную привязку Сетки событий.

Существует два варианта для вывода сообщения Сетки событий из функции:

  • Возвращаемое значение: задайте name для свойства в function.json значение $return. В этой конфигурации возвращаемое значение функции сохраняется как сообщение Сетки событий.
  • Императив. Передайте значение в метод set параметра, объявленного как тип Out . Значение, переданное методу set, сохраняется как сообщение Сетки событий.

Связи

Существует два способа проверки подлинности в разделе сетки событий при использовании выходной привязки сетки событий:

Authentication method Description
Использование ключа раздела TopicEndpointUri Задайте параметры и TopicKeySetting свойства, как описано в разделе "Использование ключа раздела".
Использование удостоверения Connection Задайте свойству имя общего префикса для нескольких параметров приложения, а также определите проверку подлинности на основе удостоверений. Этот метод поддерживается при использовании расширения версии 3.3.x или выше.

Использование ключа раздела

Чтобы настроить ключ раздела, выполните следующие действия.

  1. Выполните действия, описанные в разделе "Получение ключей доступа", чтобы получить ключ раздела для раздела "Сетка событий".

  2. В параметрах приложения создайте параметр, определяющий значение ключа раздела. Используйте имя этого параметра для TopicKeySetting свойства привязки.

  3. В параметрах приложения создайте параметр, определяющий конечную точку раздела. Используйте имя этого параметра для TopicEndpointUri свойства привязки.

Проверка подлинности на основе удостоверений

При использовании расширения версии 3.3.x или более поздней версии вы можете подключиться к разделу Сетки событий с помощью удостоверения Microsoft Entra, чтобы избежать необходимости получать и работать с ключами раздела.

Необходимо создать параметр приложения, который возвращает универсальный код ресурса (URI) конечной точки раздела. Имя параметра должно сочетать уникальный общий префикс (например, myawesometopic) со значением __topicEndpointUri. Затем необходимо использовать общий префикс (в данном случае myawesometopic) при определении Connection свойства в привязке.

В этом режиме для расширения требуются следующие свойства:

Свойство Шаблон переменной среды Description Пример значения
URI конечной точки раздела <CONNECTION_NAME_PREFIX>__topicEndpointUri Конечная точка раздела. https://<topic-name>.centralus-1.eventgrid.azure.net/api/events

Дополнительные свойства можно использовать для настройки подключения. См. раздел Общие свойства подключений на основе удостоверений.

Примечание.

При использовании Конфигурация приложений Azure или Key Vault для предоставления параметров для подключений на основе управляемых удостоверений имена должны использовать допустимый разделитель ключей, например : или / вместо __ них, чтобы обеспечить правильное разрешение имен.

Например, <CONNECTION_NAME_PREFIX>:topicEndpointUri.

При размещении в службе "Функции Azure" для подключений на основе удостоверений используется управляемое удостоверение. По умолчанию используется назначаемое системой удостоверение, однако вы можете указать назначаемое пользователем удостоверение с помощью свойств credential и clientID. Обратите внимание, что настройка назначаемого пользователем удостоверения с идентификатором ресурса не поддерживается. При выполнении в других контекстах, например при локальной разработке, вместо этого используется удостоверение разработчика, хотя это можно настроить. См. раздел Локальная разработка с использованием подключений на основе удостоверений.

Предоставление разрешения удостоверению

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

Внимание

Иногда целевая служба может предоставлять разрешения, которые не являются обязательными для всех контекстов. Там, где это возможно, придерживайтесь принципа минимальных привилегий, предоставляя удостоверению лишь самые необходимые привилегии. Например, если приложению требуется только возможность чтения из источника данных, используйте роль, которая имеет разрешение только на чтение. Было бы неуместным назначить роль, которая также разрешает запись в эту службу, так как это разрешение не требуется для операции чтения. Соответственно необходимо еще проверить, что область действия назначенной роли ограничена только теми ресурсами, которые необходимо прочитать.

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

Тип привязки Примеры встроенных ролей
Выходные привязки Участник EventGrid, отправитель данных EventGrid

Следующие шаги