Mengekspor dan mengimpor pendaftaran Azure Notification Hubs secara massal

Ada skenario saat harus membuat atau mengubah sejumlah besar pendaftaran di hub notifikasi. Beberapa skenario ini adalah pembaruan tag setelah komputasi batch, atau memigrasikan implementasi push yang ada untuk menggunakan Azure Notification Hubs.

Artikel ini menjelaskan cara melakukan operasi dalam jumlah besar di hub notifikasi, atau untuk mengekspor semua pendaftaran secara massal.

CATATAN: Impor/ekspor massal hanya tersedia untuk tingkat harga 'standar'

Alur tingkat tinggi

Dukungan batch dirancang untuk mendukung pekerjaan jangka panjang yang melibatkan jutaan pendaftaran. Untuk mencapai skala ini, dukungan batch menggunakan Azure Storage untuk menyimpan detail dan output pekerjaan. Untuk operasi pembaruan massal, pengguna harus membuat file dalam kontainer blob, yang isinya adalah daftar operasi pembaruan pendaftaran. Saat memulai pekerjaan, pengguna memberikan URL ke blob input, bersama dengan URL ke direktori output (juga dalam kontainer blob). Begitu pekerjaan dimulai, pengguna bisa memeriksa status dengan meng-kueri lokasi URL yang disediakan di awal pekerjaan. Pekerjaan tertentu hanya bisa menjalankan operasi dengan jenis tertentu (membuat, memperbarui, atau menghapus). Operasi ekspor dilakukan secara analog.

Impor

Menyiapkan

Bagian ini mengasumsikan Anda memiliki entitas berikut:

Membuat file input dan menyimpannya dalam blob

File input berisi daftar pendaftaran yang dimuat berseri dalam XML, satu per baris. Menggunakan Azure SDK, contoh kode berikut menunjukkan cara membuat serialisasi pendaftaran dan mengunggahnya ke kontainer blob:

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);
     }
}

Penting

Kode sebelumnya membuat serialisasi pendaftaran dalam memori lalu mengunggah seluruh aliran ke dalam blob. Jika Anda telah mengunggah file lebih dari beberapa megabyte, lihat panduan blob Azure tentang cara melakukan langkah-langkah ini; misalnya, blok blob.

Membuat token URL

Setelah file input Anda diunggah, buat URL yang akan disediakan pada hub notifikasi untuk file input dan direktori output. Anda bisa menggunakan dua kontainer blob berbeda untuk input dan output.

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);
}

Mengirimkan pekerjaan

Dengan dua URL input dan output, Anda kini dapat memulai pekerjaan batch.

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--;
}

Selain URL input dan output, contoh ini membuat objek NotificationHubJob yang berisi objek JobType, yang dapat berupa salah satu jenis berikut:

  • ImportCreateRegistrations
  • ImportUpdateRegistrations
  • ImportDeleteRegistrations

Begitu panggilan selesai, pekerjaan dilanjutkan oleh hub notifikasi, dan Anda dapat memeriksa statusnya dengan panggilan ke GetNotificationHubJobAsync.

Saat pekerjaan selesai, Anda bisa memeriksa hasilnya dengan melihat file berikut di direktori output:

  • /<hub>/<jobid>/Failed.txt
  • /<hub>/<jobid>/Output.txt

File ini berisi daftar operasi yang berhasil dan gagal dari batch Anda. Format file adalah .cvs, dengan setiap baris berisi nomor baris file input asli dan output operasi (biasanya deskripsi pendaftaran yang dibuat atau diperbarui).

Kode sampel penuh

Kode sampel berikut akan mengimpor pendaftaran ke hub notifikasi.

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);

        }
    }
}

Ekspor

Cara mengekspor pendaftaran sama dengan mengimpor, dengan perbedaan berikut:

  • Anda hanya perlu URL output.
  • Anda membuat NotificationHubJob jenis ExportRegistrations.

Cuplikan kode sampel

Berikut ini cuplikan kode sampel untuk mengekspor pendaftaran di 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;
}

Langkah berikutnya

Untuk mempelajari selengkapnya tentang reservasi, lihat artikel berikut: