Экспорт и импорт регистраций центров уведомлений Azure в групповой операции
Существуют сценарии, в которых требуется создание или изменение большого числа регистраций в концентраторе уведомлений. Некоторые из этих сценариев представляют собой обновления тегов, которые выполняются с помощью пакетных вычислений, или миграцию существующей реализации push-уведомлений для использования концентраторов уведомления Azure.
В этой статье объясняется, как выполнить большое количество операций в концентраторе уведомлений или экспортировать все регистрации.
ПРИМЕЧАНИЕ: Массовый импорт и экспорт доступен только для ценовой категории "Стандартный"
Поток высокого уровня
Пакетная поддержка обеспечивает долговременные задания, связанные с миллионами регистраций. Для достижения этого масштаба Пакетная поддержка использует службу хранилища Azure для хранения сведений о заданиях и выходных данных. Для операций пакетного обновления пользователю требуется создать файл в контейнере больших двоичных объектов, содержимое которого является списком регистрации операций обновления. При запуске задания пользователь предоставляет URL-адрес для входного большого двоичного объекта вместе с URL-адресом для выходного каталога (а также для контейнера больших двоичных объектов). После запуска задания пользователь может проверить состояние, запросив URL-адрес, указанный при запуске задания. Конкретное задание может выполнять только операции определенного типа (создание, обновление или удаление). Операции экспорта выполняются аналогично.
Импорт
Настройка
В этом разделе предполагается наличие следующих компонентов:
- Провизионированный концентратор уведомлений.
- Контейнер больших двоичных объектов хранилища Azur.
- Ссылки на пакет NuGet для службы хранилища Azure и пакет NuGet для концентраторов уведомлений.
Создание входного файла и сохранение его в контейнере больших двоичных объектов
Входной файл содержит список регистраций, сериализованных в XML-коде, по одной на строку. При использовании Azure SDK, следующий пример кода показывает, как проводится сериализация регистраций и передача их в контейнер больших двоичных объектов.
private static async Task SerializeToBlobAsync(BlobContainerClient container, RegistrationDescription[] descriptions)
{
StringBuilder builder = new StringBuilder();
foreach (var registrationDescription in descriptions)
{
builder.AppendLine(registrationDescription.Serialize());
}
var inputBlob = container.GetBlobClient(INPUT_FILE_NAME);
using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(builder.ToString())))
{
await inputBlob.UploadAsync(stream);
}
}
Важно!
Предыдущий код сериализует регистрации в памяти и затем передает весь поток в контейнер больших двоичных объектов. Если передается файл размером больше, чем несколько мегабайт, то см. инструкцию по большим двоичным объектам Azure. Например, большие двоичные объекты блочного типа.
Создание токенов URL-адресов
После отправки входного файла создайте URL-адреса для предоставления концентратору уведомлений как для входного файла, так и для выходного каталога. Для ввода и вывода можно использовать два разных контейнера больших двоичных объектов.
static Uri GetOutputDirectoryUrl(BlobContainerClient container)
{
Console.WriteLine(container.CanGenerateSasUri);
BlobSasBuilder builder = new BlobSasBuilder(BlobSasPermissions.All, DateTime.UtcNow.AddDays(1));
return container.GenerateSasUri(builder);
}
static Uri GetInputFileUrl(BlobContainerClient container, string filePath)
{
Console.WriteLine(container.CanGenerateSasUri);
BlobSasBuilder builder = new BlobSasBuilder(BlobSasPermissions.Read, DateTime.UtcNow.AddDays(1));
return container.GenerateSasUri(builder);
}
отправить задание.
Теперь с двумя входными и выходными URL-адресами можно запустить пакетное задание.
NotificationHubClient client = NotificationHubClient.CreateClientFromConnectionString(CONNECTION_STRING, HUB_NAME);
var job = await client.SubmitNotificationHubJobAsync(
new NotificationHubJob {
JobType = NotificationHubJobType.ImportCreateRegistrations,
OutputContainerUri = outputContainerSasUri,
ImportFileUri = inputFileSasUri
}
);
long i = 10;
while (i > 0 && job.Status != NotificationHubJobStatus.Completed)
{
job = await client.GetNotificationHubJobAsync(job.JobId);
await Task.Delay(1000);
i--;
}
В дополнение к URL-адресам входа и выхода в этом примере создается объект NotificationHubJob
, которые содержит один из объектовJobType
следующего типа:
ImportCreateRegistrations
ImportUpdateRegistrations
ImportDeleteRegistrations
После завершения вызова концентратор уведомлений продолжает выполнение задания, состояние которого можно проверить с помощью вызова в GetNotificationHubJobAsync.
По завершении выполнения задания можно проверить результаты, просмотрев следующие файлы в выходном каталоге:
/<hub>/<jobid>/Failed.txt
/<hub>/<jobid>/Output.txt
Эти файлы содержат список успешных и неудачных операций из пакета. Файл создается в формате .cvs
, в котором в каждой строке имеется номер исходного входного файла и выхода операции (обычно созданное или обновленное описание регистрации).
Полный образец кода
В следующем примере кода выполняется импорт регистраций в концентратор уведомлений.
using Microsoft.Azure.NotificationHubs;
using Azure.Storage.Blobs;
using Azure.Storage.Sas;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
private static string CONNECTION_STRING = "namespace";
private static string HUB_NAME = "demohub";
private static string INPUT_FILE_NAME = "CreateFile.txt";
private static string STORAGE_ACCOUNT_CONNECTIONSTRING = "connectionstring";
private static string CONTAINER_NAME = "containername";
static async Task Main(string[] args)
{
var descriptions = new[]
{
new MpnsRegistrationDescription(@"http://dm2.notify.live.net/throttledthirdparty/01.00/12G9Ed13dLb5RbCii5fWzpFpAgAAAAADAQAAAAQUZm52OkJCMjg1QTg1QkZDMkUxREQFBlVTTkMwMQ"),
new MpnsRegistrationDescription(@"http://dm2.notify.live.net/throttledthirdparty/01.00/12G9Ed13dLb5RbCii5fWzpFpAgAAAAADAQAAAAQUZm52OkJCMjg1QTg1QkZDMjUxREQFBlVTTkMwMQ"),
new MpnsRegistrationDescription(@"http://dm2.notify.live.net/throttledthirdparty/01.00/12G9Ed13dLb5RbCii5fWzpFpAgAAAAADAQAAAAQUZm52OkJCMjg1QTg1QkZDMhUxREQFBlVTTkMwMQ"),
new MpnsRegistrationDescription(@"http://dm2.notify.live.net/throttledthirdparty/01.00/12G9Ed13dLb5RbCii5fWzpFpAgAAAAADAQAAAAQUZm52OkJCMjg1QTg1QkZDMdUxREQFBlVTTkMwMQ"),
};
// Get a reference to a container named "sample-container" and then create it
BlobContainerClient container = new BlobContainerClient(STORAGE_ACCOUNT_CONNECTIONSTRING, CONTAINER_NAME);
await container.CreateIfNotExistsAsync();
await SerializeToBlobAsync(container, descriptions);
// TODO then create Sas
var outputContainerSasUri = GetOutputDirectoryUrl(container);
BlobContainerClient inputcontainer = new BlobContainerClient(STORAGE_ACCOUNT_CONNECTIONSTRING, STORAGE_ACCOUNT_CONNECTIONSTRING + "/" + INPUT_FILE_NAME);
var inputFileSasUri = GetInputFileUrl(inputcontainer, INPUT_FILE_NAME);
// Import this file
NotificationHubClient client = NotificationHubClient.CreateClientFromConnectionString(CONNECTION_STRING, HUB_NAME);
var job = await client.SubmitNotificationHubJobAsync(
new NotificationHubJob {
JobType = NotificationHubJobType.ImportCreateRegistrations,
OutputContainerUri = outputContainerSasUri,
ImportFileUri = inputFileSasUri
}
);
long i = 10;
while (i > 0 && job.Status != NotificationHubJobStatus.Completed)
{
job = await client.GetNotificationHubJobAsync(job.JobId);
await Task.Delay(1000);
i--;
}
}
private static async Task SerializeToBlobAsync(BlobContainerClient container, RegistrationDescription[] descriptions)
{
StringBuilder builder = new StringBuilder();
foreach (var registrationDescription in descriptions)
{
builder.AppendLine(registrationDescription.Serialize());
}
var inputBlob = container.GetBlobClient(INPUT_FILE_NAME);
using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(builder.ToString())))
{
await inputBlob.UploadAsync(stream);
}
}
static Uri GetOutputDirectoryUrl(BlobContainerClient container)
{
Console.WriteLine(container.CanGenerateSasUri);
BlobSasBuilder builder = new BlobSasBuilder(BlobSasPermissions.All, DateTime.UtcNow.AddDays(1));
return container.GenerateSasUri(builder);
}
static Uri GetInputFileUrl(BlobContainerClient container, string filePath)
{
Console.WriteLine(container.CanGenerateSasUri);
BlobSasBuilder builder = new BlobSasBuilder(BlobSasPermissions.Read, DateTime.UtcNow.AddDays(1));
return container.GenerateSasUri(builder);
}
}
}
Экспорт
Регистрация экспорта похожа на регистрацию импорта, но имеет следующие отличия:
- Необходим только выходной URL-адрес.
- Вы создаете NotificationHubJob типа ExportRegistrations.
Пример фрагмента кода
Ниже приведен пример фрагмента кода для экспорта регистраций в Java.
// Submit an export job
NotificationHubJob job = new NotificationHubJob();
job.setJobType(NotificationHubJobType.ExportRegistrations);
job.setOutputContainerUri("container uri with SAS signature");
job = hub.submitNotificationHubJob(job);
// Wait until the job is done
while(true){
Thread.sleep(1000);
job = hub.getNotificationHubJob(job.getJobId());
if(job.getJobStatus() == NotificationHubJobStatus.Completed)
break;
}
Дальнейшие действия
Дополнительные сведения о регистрациях см. в следующих статьях: