Создание простых функций для сложного потока

В статье ниже будет показано, как создаются простые функции для создания сложного потока. В этом подробном посте вы узнаете, как именно это будет происходить.

В предыдущем посте я разработал переводчик некоторых реляционных данных в данные событий. Теперь я воспользуюсь переводчиком, чтобы перенести музыкальную композицию из детского инструмента композиции ikcomponeer.nl (Flash и mySQL / PHP) в новую среду инструмента композиции (HTML, JavaScript и Azure).

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

Давайте начнем с отметки «перенесено» в таблице устаревшей базы данных, из которой мы выполняем миграцию.

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

Вот сама функция. Вы можете увидеть выходной параметр с именем compositionToMigrate и строковый ввод. Вход не важен; это просто строка, которая создается при нажатии кнопки run вручную.

Затем функция выполняет следующие действия:

  1. Получите самую последнюю неперенесенную композицию id из старой среды mySQL / PHP.
  2. Назначьте этот id очереди вывода.
  3. Снова вызовите старую среду, чтобы убедиться, что id можно пометить как перенесенную.

Мы можем увидеть результат, осмотрев очередь.

И, конечно же, это также должно привести к тому, что композиция будет помечена как migrated в базе данных.

Извлеките данные из исходной системы и храните в центре обработки данных Azure

Мы создадим функцию, которая будет запускаться при появлении нового идентификатора композиции в очереди. Он загрузит все данные композиции, включая все данные, от которых она зависит, такие как настройки, используемые музыкальные коллекции и т. Д. Затем функция сохранит эти данные в хранилище BLOB-объектов.

Итак, вот функция, она очень простая!

Я могу попробовать это, вручную взяв идентификатор с первой функцией запуска ... и он показывает в контейнере, что есть некоторые данные.

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

Переводчик и его группы событий

Теперь, когда у нас есть данные, защищенные в хранилище BLOB-объектов, мы можем использовать их в качестве отправной точки для преобразования в управляемую событиями форму.

События хранятся в четырех разных таблицах хранилища Azure, предназначенных для обеспечения необходимого распределения и доступности. Эти четыре таблицы основаны на четырех реальных приложениях или использовании данных. Следовательно, они связаны определенным образом.

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

Четыре таблицы хранилища Azure

  1. Данные музыкальной композиции.
  2. Данные конфигурации проекта (многие композиции используют одну и ту же конфигурацию, когда дело доходит до конфигурации приложения и окружающей веб / сетевой среды).
  3. Данные музыкальной среды (многие композиции используют один и тот же набор исходных файлов MP3 и других музыкальных параметров, таких как темп).
  4. Данные прокрутки (список других композиций, доступных при работе над этой композицией, чтобы пользователь мог вводить множество видов музыки и впечатлений).

В следующих главах более подробно рассказывается о различных типах данных.

Данные музыкальной среды

Эти данные предоставляет музыкальный продюсер, который создает группы аудиоклипов, из которых дети могут сочинять музыку. Можно создавать различные комбинации инструментальных фраз (партий), таких как дерево, перкуссия, медь, а также нетрадиционные или творческие комбинации.

Один и тот же набор клипов можно использовать в качестве исходного материала для создания нескольких организаций из этих клипов, используя следующие события. Этот тип событий отмечен интерфейсом IMusicEnvironmentEvent.

Данные конфигурации проекта

Конфигурация проекта не касается самих музыкальных данных. Он касается конфигурации приложения, в котором пользователь может использовать музыкальные данные.

Например:

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

И так далее. Все, что приложение может делать и может быть настроено, относится к этой группе.

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

Данные конфигурации проекта обычно создаются разработчиками проекта и консультантами по приложениям, которые могут помочь в реализации конкретной установки, конфигурации или способа использования. Они также могут помочь с техническими интерфейсами, чтобы инструмент композиции по-разному взаимодействовал с сайтами встраивания.

Есть много видов таких Config событий (их слишком много, чтобы поместиться на картинке), но вот впечатление.

Прокрутка событий

Хотя конфигурация предназначена для настройки различных способов использования музыкальных наборов, прокрутка представляет собой список конкретных начальных проектов - композиций, которые содержат музыкальную среду, данные конфигурации и данные композиции).

Список называется свиток, потому что, когда вы находитесь на веб-сайте (например, в пространстве композиции школы или образовательном веб-сайте оркестра), вы можете прокручивать список и нажимать стартовый состав.

События прокрутки самые простые. Это просто названия и идентификаторы композиций.

Состав События

События композиции - это фактически сочиненная музыка, созданная конечным пользователем.

Другие ожидаемые события

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

Есть и другие предсказуемые события, которые мы хотим сохранить. Например, когда пользователь перемещает событие на дорожку или нажимает кнопку для прослушивания музыки или для запуска другого поведения пользовательского интерфейса (например, прослушивания подсказок справки Audible).

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

Функция переводчика

Функция переводчика сохранит приведенные выше списки событий в большом двоичном объекте. Сохраняя эти данные в большом двоичном объекте, мы можем создать другую функцию для реализации других функций (в другой функции), которая будет иметь дело со спецификой хранилища таблиц Azure.

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

Включая переводчика

Переводчик - это сам по себе проект с юнит-тестами и всем остальным. Он состоит из среды сборки с тестами, которые автоматически отправляют библиотеку на платформу управления пакетами NuGet.

Вот мой исходный код:



И получившийся пакет NuGet:



Чтобы использовать переводчик в функции, мы должны включить этот пакет NuGet. Сначала мы создаем пустую функцию на основе доступного шаблона «триггер большого двоичного объекта».

Затем мы переходим к специальным инструментам и выбираем среду Kudu.

Мы редактируем project.json файл так, чтобы мы ссылались на пакет, который нам нужно импортировать; пакет из нашего собственного пакета NuGet.

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

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

Давайте настроим / привяжем другой контейнер хранилища BLOB-объектов для хранения событий.

Вы можете увидеть, что внутри библиотеки переводчика ToString() реализована следующая реализация:

При сериализации все объекты будут иметь имя класса как стандартное поле, так что десериализация также станет возможной. Например:

Сохранение в blob теперь стало проще; нам нужно только добавить привязку в качестве аргумента функции (параметр out) и присвоить ему строку. Фреймворк позаботится о том, чтобы он был сохранен в большом двоичном объекте.

Давайте посмотрим, что произойдет, когда мы вручную запустим первую из функций в цепочке. В разделе «Монитор» мы видим, что в результате наша новая функция также была запущена.

А в нашем хранилище есть новая запись blob.

Он должен содержать наши данные в виде событий. Давайте посмотрим, как это выглядит, и подумаем, как мы можем хранить их в хранилище таблиц.

Очень хорошо! Имя класса было правильно сохранено в поле Type, поэтому десериализовать события из хранилища BLOB-объектов не должно быть слишком сложно.

Объектно-реляционное сопоставление, управляемое доменом

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

  1. Во-первых, это элементы прокрутки (создаются и изменяются модератором контента).
  2. Во-вторых, у вас есть элементы конфигурации (созданные и измененные техническим специалистом, например разработчиком инструмента композиции).
  3. В-третьих, это параметры музыкальной среды, такие как наличие музыкальных клипов для сочинения, созданные консультантом вместе с производителем исходного музыкального материала.
  4. И последнее, но не менее важное: есть события композиции конечным пользователем, пример которых вы можете увидеть на изображении выше.

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

В нашем трансляторе мы уже реализовали поле, которое будет давать уникальный идентификатор для данных прокрутки, данных конфигурации, данных среды и данных композиции. Эти идентификаторы хранятся в событии, созданном композицией.

При миграции мы можем предположить, что, когда мы уже сохранили элемент с этим идентификатором ранее, нам не придется делать это снова, поскольку он уже будет там.

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

Итак, нашей новой функции требуется входная привязка из большого двоичного объекта с сериализованными данными события. Для привязок вывода нам нужны данные прокрутки, среды и конфигурации, но нам нужно будет проверить наличие элементов.

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

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

Это необходимо, потому что старая версия внешнего интерфейса также не хранит данные о событиях. Однако в будущем с новой (JavaScript, а не Flash) версией внешнего интерфейса все действия редактирования будут просто приводить к добавлению новых событий в тот же поток.

Дифференциация учетных записей хранения

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

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

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

Затем у вас есть данные о композиции, которые обычно используются локально, но меняются и должны обеспечивать совместную работу в реальном времени. Из-за всех этих разных характеристик я, честно говоря, не знаю, как будет развиваться масштабирование.

По крайней мере, я создал четыре разных учетных записи хранения:

Дизайн функции StoreEventsInTables

Создание самой функции - запускаемой функции blob в C #.

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

После этого, когда мы вернемся к файлу C # run.csx, компилятор начнет жаловаться на отсутствие аргументов, названных в честь наших привязок. Он будет счастлив только тогда, когда мы определим эти аргументы.

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

Десериализация для ввода с использованием универсального кода

Эта часть оказалась неожиданно сложной. Как выполнить десериализацию из JSON в какой-то список с различными классами в нем, если вы знаете имена этих классов в десериализованном объекте и не хотите писать несколько строк кода для каждого из отдельных классов?

Почесав голову и погуглив, я нашел способ десериализации в определенный тип, но не очень общий. Я должен был явно сказать компилятору, что это будет:

Мне потребовалось еще немного времени, чтобы создать экземпляр объекта в его надлежащем типе, но в конце концов мне это удалось.

И я использовал интерфейсы маркеров, чтобы определить, какое событие в какой таблице должно храниться. Я должен уметь их различать - и это работает!

Состав ключей строк и ключей разделов для событий

Как объяснялось выше, я использовал событие, созданное композицией, для хранения идентификаторов потоков событий различных «бизнес-сессий».

Их можно использовать как ключи раздела. Затем в качестве ключей строки можно использовать инкрементное число.

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

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

Это своего рода код, который даст нам некоторые ключи хранилища:

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

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

Теперь, когда я нахожусь в поезде, служба потоковой передачи журналов мне ничего не показала! К счастью, у нас есть страница монитора, на которой мы видим, что запуск прошел успешно.

Когда я щелкаю эту строку, я все еще могу видеть детали вызова. Выглядит очень хорошо!

Но самое лучшее еще впереди ... наши данные в хранилище таблиц!

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

На самом деле «пустые поля» в таблицах не теряются - каждая строка имеет свою собственную структуру, и каждая строка уникальна. Это может стать трудночитаемым в обозревателе хранилища, но это не так важно.

Когда мы привыкли к способу отображения, мы можем обнаружить, что в таблице есть три типа. Номер 0 - это ClearComposition событие. У него нет полей. Это своего рода маркер, который сообщает приложению выгрузить существующую память или хранилище.

Второй (вы можете видеть, что у него следующий RowKey) явно является CompositionCreated событием. У него есть название композиции и все идентификаторы других сущностей, от которых он зависит. Третий и все остальные - это события, с помощью которых музыкальные клипы добавляются в композицию.

Однако есть проблема: Тип не сохраняется!

Удаление предыдущих записей

Поскольку я допустил ошибку программирования с типом (который мне нужно исправить), я должен удалить все строки данных композиции с определенным ключом раздела. Кроме того, когда пользователь сохраняет новую версию композиции, а в этой новой версии она перенесена, ему придется перезаписать старую версию. Итак, теперь необходимо удалить все строки с ключом раздела.

Я создал следующий код, который должен удалить все строки из конкретной композиции.

И удалил ли он мои фактические строки из хранилища таблиц?

Да!

Исправление поля типа

Над реализацией я работал, но только с сериализацией. Чтобы он работал и как объект таблицы, старая версия не работала. Это была старая версия.

У поля, конечно же, должны быть обычные геттер и сеттер. Чтобы по-прежнему заполнять поле автоматически, я использовал конструктор. Я чувствую, что это немного странно, и надеюсь, что в будущем это не доставит мне проблем.

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

Вставить, когда не существует, в противном случае ничего не делать

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

Упрощение хранения

Когда я снова отбросил данные, мои четыре таблицы хранилища были заполнены. Я мог видеть, как все находится в таблицах хранения. Но не было полей, в которых я ожидал бы перечислимые типы.

Я посмотрел на API Flatten и класс DynamicTableEntity. Однако меня уже вполне устраивает сериализация JSON, и я не хочу добавлять больше уязвимостей, используя больше методов. Я не планирую фактически использовать поля в контексте хранения таблиц как таковых, поэтому я мог бы также сериализовать их и сделать все намного проще.

Разделение между доменом хранения и доменом приложения становится более четким. Однако это означает, что мне нужно удалить наследование типа TableEntity из всех моих классов.

SerializedEntity - это тот, который я буду использовать для всех моих сохраненных данных.

Прохождение финального результата

Конечный результат кода становится немного проще. Я просто создаю четыре однотипных списка. Единственное различие - это ключи разделов и, по причинам, объясненным ранее, дифференциация их учетных записей хранения по причинам распределения / масштабируемости / оптимизации.

Судя по журналам, эта часть функции работает нормально:

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

Как мы видим в журнале, это тоже работает.

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

По метке времени таблицы хранения мы видим, что композиция действительно была перезаписана.

Остальные три агрегата никогда не изменятся во время миграции. Следовательно, нам нужно сохранить их только один раз. Потому что прочитать одну запись значительно дешевле, чем перезаписать всю партию. Сделав такой код, мы сэкономим сотни миллионов операций записи.

Мы видим в журнале, что это работает.

Также по метке времени видно, что она старше композиции.

Теперь, когда все вроде работает, мы можем снова пройти весь поток.

Регрессионное тестирование всего потока

Когда мы внесли некоторые изменения в нашу библиотеку NuGet в нескольких нижестоящих функциях, мы можем спросить: «Нужно ли нам вносить эти изменения и в вышестоящие функции?»

Это помогает, когда мы просматриваем природу этих изменений и можем предсказать, нужно ли нам обновить вышестоящие функции до более новой версии пакета.

Итак, мы снова возвращаемся к первой функции.

Повторное посещение MarkCompositionsForMigration

Эта функция, похоже, ничего не делает с библиотекой - она ​​просто берет числовой идентификатор из PHP API, помещает его в очередь и подтверждает с помощью функции setMigratedFlag, снова используя только идентификатор.

Чтобы убедиться в этом, можно посмотреть project.json файл функции.

Возвращение к LoadDataFromSourceSystemToBlob

Эта функция просто загружает большой объем сериализованных данных JSON из серверной части PHP и безопасно сохраняет их в центре обработки данных Azure с помощью выходной привязки Blob (hierarchicalCompositionData). Итак, опять же, наш пакет NuGet не используется.

Еще раз о TranslateToEvents

Эта функция использует фактический транслятор для загрузки данных композиции, взятых из серверной части PHP, и для их преобразования в сериализованные события, введенные в домене нашего пакета .NET NuGet.

В нашем пакете используется более старая версия. Текущая версия - Install-Package 1.0.0-CI-20190529–063832.

Вот как используется пакет:

Давайте рассмотрим изменения кода, которые были внесены с момента выхода этой версии пакета NuGet.

Действительно, в этот день мы можем найти сборку, отправленную в NuGet с этой версией.

Название сборки сразу показывает, какой коммит мне следует искать на GitHub.

Теперь я могу просмотреть все изменения, чтобы предсказать, лучше ли изменить версию или нет.

В этом случае я решил обновить функцию, что вы обычно и хотите.

Повторное тестирование всего потока

Поскольку мы обновили наши пакеты, давайте еще раз протестируем весь поток. Он начинается с ручного запуска первой функции, а после этого должны запускаться четыре функции подряд.

В результате появляется сообщение об успехе в журнале.

Посмотрим, успешно ли работают и другие функции на этот раз.

Так что… выглядит хорошо! А как насчет результатов?

Тестирование результата в исходной системной базе данных

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

Проверка хранилища BLOB-объектов

Я вижу, что в этот день в контейнере хранения для иерархических / непреобразованных исходных данных есть большой двоичный объект.

При загрузке капли я вижу, что это действительно ожидаемая композиция.

Кроме того, на месте преобразованных сериализованных данных есть новый большой двоичный объект.

При загрузке этого блоба я получаю хорошее впечатление о данных внутри.

Самый важный объект - это событие «композиция создана», где мы найдем ключи секций других агрегатов.

Осмотр столов для хранения

Таблицы environment, project / conf и scroll не обновлялись, потому что эти объекты уже были сохранены. Сам же состав был обновлен.

Замена ручного триггера на таймер

Для переноса всех композиций воспользуемся таймером. Как быстро мы должны отпустить таймер? Мы надеемся, что старая база данных PHP не будет перегружена нашими запросами, но с другой стороны, мы хотим перенести все композиции за два месяца. Сколько секунд в двух месяцах? 5 184 000 секунд. Сколько композиций в базе? 104 000.

Итак, ответ на наш вопрос - 5,184,000 / 104,559.

Композиция должна будет мигрировать каждые 49 секунд, чтобы мы были готовы через два месяца. Давайте округлим это до одной минуты, и это займет два месяца и около десяти дней.

Итак, как мы можем изменить ручной триггер для триггера таймера?

Во-первых, давайте удалим ручной триггер.

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

В журнале я вижу, что есть ошибка, говорящая мне, что я должен добавить аргумент myTimer в профиль функции.

Теперь я вижу, что функция запускается каждую минуту.

Это должно привести к тому, что некоторые капли будут добавляться каждую минуту!

Увидим ли мы что-нибудь и в хранилище таблиц?

Да ... работает!

Мониторинг

Т.к. я хочу видеть, как это происходит каждый день. Я надеюсь, что кое-что из того, что я предоставил, уже "из коробки" ...

Аналитика приложений

Я вижу некоторые запросы на странице аналитики Application Insights. Мне не нужно было это настраивать; видимо выходит из коробки.

Я не знаю точно, что это за язык, но мне удалось легко включить все такие функции, как это:

Теперь мне удалось получить только неудачные.

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

Что ж, это хорошо, но я не вижу много журналов. К счастью, в Application Insights есть и другие полезности.

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

Через этот интерфейс я нашел данные этого вызова. Я использовал кнопку view all telemetry around this time, чтобы увидеть больше, и немного скорректировал временное окно телеметрии.

Затем я обнаружил, что, по всей видимости, данные о блобах, которые привели к ошибкам, перемещаются в подозрительную очередь!

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

Но это не так-то просто. Мне пришлось бы вручную открывать все сообщения в очереди и вручную искать и загружать все файлы BLOB-объектов. Итак, я собираюсь написать еще одну функцию, чтобы скопировать неудачные данные в специальный контейнер больших двоичных объектов. Контейнер будет называться failing-data.

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

Чтобы десериализовать требуемые свойства из сообщения, вы должны создать класс и классифицировать привязку как этот настраиваемый класс.

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

Сначала я добавляю связыватель в свою функцию. Затем я могу использовать этот стиль привязки для записи чего-либо в большой двоичный объект с динамическим путем. Первый сегмент пути - это контейнер большого двоичного объекта. Другие сегменты - это дальнейшие каталоги в пути и, наконец, имя файла.

Теперь, как мы можем использовать PoisonMessage ContainerName и BlobName для динамического чтения из соответствующего контейнера?

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

Очередь теперь должна быть пустой, а это:

Самое главное, мы должны найти наши неудачные капли в нашем только что созданном контейнере:

Теперь пришло время легко загрузить все эти капли сразу и посмотреть, что пошло не так. Однако на первый взгляд я не вижу ничего плохого в данных.

Давайте снова заглянем в аналитику приложений, чтобы найти само исключение.

При осмотре отказов первое, что мы можем увидеть, - это то, что числа складываются. Было 10 больших двоичных объектов с ошибочными данными и всего 50 исключений, потому что каждый большой двоичный объект повторяется четыре раза, что составляет пять выполнений на один неудачный большой двоичный объект.

Также мы видим два типа исключений - недопустимое приведение и исключение с нулевой ссылкой.

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

После некоторого щелчка я перехожу к фактической ошибке, и она очень подробная!

И это правда. В моих данных NotePad ++ JSON я теперь могу обнаружить, что это так.

Возможно, эти композиции были не очень хорошо скомпонованы, потому что на самом деле они никогда не производились, а были студенческим проектом, экспериментом.

В результате этого эксперимента было получено девять ядовитых файлов, а также девять недопустимых исключений приведения, что не случайно. Я не собираюсь ничего исправлять и рассматриваю эти данные как ненужные данные, которые не будут переноситься.

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

Заключение

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

Пожалуйста, оставьте свой отзыв ниже.