내보내기(0) 인쇄
모두 확장

Media Services 작업 알림 처리

업데이트 날짜: 2014년 7월

Microsoft Azure 미디어 서비스는 미디어 작업을 처리할 때 Azure 큐 저장소(영문)로 알림 메시지를 배달할 수 있습니다. 이 항목에서는 큐 저장소에서 이러한 알림 메시지를 가져오는 방법을 보여 줍니다.

큐 저장소에 배달된 메시지는 세계 어디에서나 액세스할 수 있습니다. Azure 큐 메시징 아키텍처는 안정적이며 확장성이 우수합니다. 다른 방법을 사용하는 대신 큐 저장소를 폴링하는 것이 좋습니다.

Media Services 알림을 수신하는 일반적인 시나리오 한 가지는 인코딩 작업을 완료한 후 워크플로의 다음 단계를 트리거하거나 콘텐츠를 게시하는 등의 일부 추가 작업을 수행해야 하는 콘텐츠 관리 시스템을 개발하는 경우입니다.

Azure 저장소 큐를 사용하는 미디어 서비스 응용 프로그램을 개발할 때 고려할 사항은 다음과 같습니다.

이 섹션의 코드 예제에서는 다음과 같은 작업을 수행합니다.

  1. 알림 메시지 형식에 매핑되는 EncodingJobMessage 클래스를 정의합니다. 이 코드는 큐에서 받은 메시지를 EncodingJobMessage 유형의 개체로 역직렬화합니다.

  2. app.config 파일에서 Media Services 및 저장소 계정 정보를 로드합니다. 이 정보를 사용하여 CloudMediaContextCloudQueue 개체를 만듭니다.

  3. 인코딩 작업에 대한 알림 메시지를 받을 큐를 만듭니다.

  4. 큐에 매핑되는 알림 끝점을 만듭니다.

  5. 알림 끝점을 작업에 연결하고 인코딩 작업을 제출합니다. 한 작업에 알림 끝점을 여러 개 연결할 수 있습니다.

    이 예에서는 작업 처리 시의 최종 상태만 확인하므로 AddNew 메서드에 NotificationJobState.FinalStatesOnly를 전달합니다.

    job.JobNotificationSubscriptions.AddNew(NotificationJobState.FinalStatesOnly, _notificationEndPoint); 
    
    NotificationJobState.All을 전달하면 대기 중 -> 예약 중 -> 처리 중 -> 완료됨의 모든 상태 변경 알림을 받게 됩니다. 하지만 앞부분에서 설명했듯이 Azure 저장소 큐 서비스가 메시지를 순서대로 배달하지 않을 수 있습니다. 아래 예의 EncodingJobMessage 유형에 정의된 Timestamp 속성을 사용하면 메시지 순서를 지정할 수 있습니다. 이 경우 중복된 알림 메시지를 받을 수 있습니다. EncodingJobMessage 유형에 정의된 ETag 속성을 사용하여 중복된 메시지가 있는지 확인합니다. 또한 일부 상태 변경 알림이 생략될 수 있습니다.

  6. 10초마다 큐를 확인하여 작업이 Finished 상태로 전환되도록 기다립니다. 처리된 메시지를 삭제합니다.

  7. 큐와 알림 끝점을 삭제합니다.

note참고
작업 상태를 모니터링할 때 다음 예에서와 같이 알림 메시지를 수신하는 것이 좋습니다.

또는 IJob.State 속성(영문)을 사용하여 작업 상태를 확인할 수 있습니다.  IJob의 State 가 Finished로 설정되기 전에 작업 완료에 대한 알림 메시지가 도착할 수 있습니다. IJob.State  속성은 약간의 지연과 함께 정확한 상태를 반영합니다.  

using System; using System.Linq; using System.Configuration; using System.IO; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Collections.Generic; using Microsoft.WindowsAzure.MediaServices.Client; using System.Web; using Microsoft.WindowsAzure.Storage; using Microsoft.WindowsAzure.Storage.Auth; using Microsoft.WindowsAzure.Storage.Queue; using System.Runtime.Serialization.Json;  namespace JobNotification {     public class EncodingJobMessage     {         // MessageVersion is used for version control.          public String MessageVersion { get; set; }              // Type of the event. Valid values are          // JobStateChange and NotificationEndpointRegistration.         public String EventType { get; set; }              // ETag is used to help the customer detect if          // the message is a duplicate of another message previously sent.         public String ETag { get; set; }              // Time of occurrence of the event.         public String TimeStamp { get; set; }          // Collection of values specific to the event.          // For the JobStateChange event the values are:         //     JobId - Id of the Job that triggered the notification.         //     NewState- The new state of the Job. Valid values are:         //          Scheduled, Processing, Canceling, Cancelled, Error, Finished         //     OldState- The old state of the Job. Valid values are:         //          Scheduled, Processing, Canceling, Cancelled, Error, Finished          // For the NotificationEndpointRegistration event the values are:         //     NotificationEndpointId- Id of the NotificationEndpoint          //          that triggered the notification.         //     State- The state of the Endpoint.          //          Valid values are: Registered and Unregistered.          public IDictionary<string, object> Properties { get; set; }     }      class Program     {         private static CloudMediaContext _context = null;         private static CloudQueue _queue = null;         private static INotificationEndPoint _notificationEndPoint = null;          private static readonly string _singleInputMp4Path =             Path.GetFullPath(@"C:\supportFiles\multifile\BigBuckBunny.mp4");          static void Main(string[] args)         {             // Get the values from app.config file.             string mediaServicesAccountName = ConfigurationManager.AppSettings["MediaServicesAccountName"];             string mediaServicesAccountKey = ConfigurationManager.AppSettings["MediaServicesAccountKey"];             string storageConnectionString = ConfigurationManager.AppSettings["StorageConnectionString"];               string endPointAddress = Guid.NewGuid().ToString();              // Create the context.              _context = new CloudMediaContext(mediaServicesAccountName, mediaServicesAccountKey);              // Create the queue that will be receiving the notification messages.             _queue = CreateQueue(storageConnectionString, endPointAddress);              // Create the notification point that is mapped to the queue.             _notificationEndPoint =                      _context.NotificationEndPoints.Create(                     Guid.NewGuid().ToString(), NotificationEndPointType.AzureQueue, endPointAddress);               if (_notificationEndPoint != null)             {                 IJob job = SubmitEncodingJobWithNotificationEndPoint(_singleInputMp4Path);                 WaitForJobToReachedFinishedState(job.Id);             }              // Clean up.             _queue.Delete();                   _notificationEndPoint.Delete();        }           static public CloudQueue CreateQueue(string storageAccountConnectionString, string endPointAddress)         {             CloudStorageAccount storageAccount = CloudStorageAccount.Parse(storageAccountConnectionString);              // Create the queue client             CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient();              // Retrieve a reference to a queue             CloudQueue queue = queueClient.GetQueueReference(endPointAddress);              // Create the queue if it doesn't already exist             queue.CreateIfNotExists();              return queue;         }            // Upload a video file, and encode to Smooth Streaming format         public static IJob SubmitEncodingJobWithNotificationEndPoint(string inputMediaFilePath)         {             // Declare a new job.             IJob job = _context.Jobs.Create("My MP4 to Smooth Streaming encoding job");              //Create an encrypted asset and upload the mp4.              IAsset asset = CreateAssetAndUploadSingleFile(AssetCreationOptions.StorageEncrypted,                  inputMediaFilePath);              // Get a media processor reference, and pass to it the name of the              // processor to use for the specific task.             IMediaProcessor processor = GetLatestMediaProcessorByName("Azure Media Encoder");              // Create a task with the conversion details, using a configuration file.              ITask task = job.Tasks.AddNew("My Mp4 to Smooth Task",                 processor,                 "H264 Smooth Streaming 720p",                 Microsoft.WindowsAzure.MediaServices.Client.TaskOptions.None);              // Specify the input asset to be encoded.             task.InputAssets.Add(asset);              // Add an output asset to contain the results of the job.             task.OutputAssets.AddNew("Output asset",                 AssetCreationOptions.None);              // Add a notification point to the job. You can add multiple notification points.               job.JobNotificationSubscriptions.AddNew(NotificationJobState.FinalStatesOnly,                  _notificationEndPoint);              job.Submit();              return job;         }          public static void WaitForJobToReachedFinishedState(string jobId)         {             int expectedState = (int)JobState.Finished;             int timeOutInSeconds = 600;              bool jobReachedExpectedState = false;             DateTime startTime = DateTime.Now;             int jobState = -1;              while (!jobReachedExpectedState)             {                 // Specify how often you want to get messages from the queue.                 Thread.Sleep(TimeSpan.FromSeconds(10));                  foreach (var message in _queue.GetMessages(10))                 {                     using (Stream stream = new MemoryStream(message.AsBytes))                     {                         DataContractJsonSerializerSettings settings = new DataContractJsonSerializerSettings();                         settings.UseSimpleDictionaryFormat = true;                         DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(EncodingJobMessage), settings);                         EncodingJobMessage encodingJobMsg = (EncodingJobMessage)ser.ReadObject(stream);                          Console.WriteLine();                          // Display the message information.                         Console.WriteLine("EventType: {0}", encodingJobMsg.EventType);                         Console.WriteLine("MessageVersion: {0}", encodingJobMsg.MessageVersion);                         Console.WriteLine("ETag: {0}", encodingJobMsg.ETag);                         Console.WriteLine("TimeStamp: {0}", encodingJobMsg.TimeStamp);                         foreach (var property in encodingJobMsg.Properties)                         {                             Console.WriteLine("    {0}: {1}", property.Key, property.Value);                         }                          // We are only interested in messages                          // where EventType is "JobStateChange".                         if (encodingJobMsg.EventType == "JobStateChange")                         {                             string JobId = (String)encodingJobMsg.Properties.Where(j => j.Key == "JobId").FirstOrDefault().Value;                             if (JobId == jobId)                             {                                 string oldJobStateStr = (String)encodingJobMsg.Properties.                                                             Where(j => j.Key == "OldState").FirstOrDefault().Value;                                 string newJobStateStr = (String)encodingJobMsg.Properties.                                                             Where(j => j.Key == "NewState").FirstOrDefault().Value;                                  JobState oldJobState = (JobState)Enum.Parse(typeof(JobState), oldJobStateStr);                                 JobState newJobState = (JobState)Enum.Parse(typeof(JobState), newJobStateStr);                                  if (newJobState == (JobState)expectedState)                                 {                                     Console.WriteLine("job with Id: {0} reached expected state: {1}",                                          jobId, newJobState);                                     jobReachedExpectedState = true;                                     break;                                 }                             }                         }                     }                     // Delete the message after we've read it.                     _queue.DeleteMessage(message);                 }                  // Wait until timeout                 TimeSpan timeDiff = DateTime.Now - startTime;                 bool timedOut = (timeDiff.TotalSeconds > timeOutInSeconds);                 if (timedOut)                 {                     Console.WriteLine(@"Timeout for checking job notification messages,                                          latest found state ='{0}', wait time = {1} secs",                         jobState,                         timeDiff.TotalSeconds);                      throw new TimeoutException();                 }             }         }             static private IAsset CreateAssetAndUploadSingleFile(AssetCreationOptions assetCreationOptions, string singleFilePath)         {             var asset = _context.Assets.Create("UploadSingleFile_" + DateTime.UtcNow.ToString(),                  assetCreationOptions);              var fileName = Path.GetFileName(singleFilePath);              var assetFile = asset.AssetFiles.Create(fileName);              Console.WriteLine("Created assetFile {0}", assetFile.Name);             Console.WriteLine("Upload {0}", assetFile.Name);              assetFile.Upload(singleFilePath);             Console.WriteLine("Done uploading of {0}", assetFile.Name);              return asset;         }          static private IMediaProcessor GetLatestMediaProcessorByName(string mediaProcessorName)         {             var processor = _context.MediaProcessors.Where(p => p.Name == mediaProcessorName).                 ToList().OrderBy(p => new Version(p.Version)).LastOrDefault();              if (processor == null)                 throw new ArgumentException(string.Format("Unknown media processor", mediaProcessorName));              return processor;         }     } } 

위 예에서는 다음 출력이 생성됩니다. 값은 다를 수 있습니다.

Created assetFile BigBuckBunny.mp4 Upload BigBuckBunny.mp4 Done uploading of BigBuckBunny.mp4  EventType: NotificationEndPointRegistration MessageVersion: 1.0 ETag: e0238957a9b25bdf3351a88e57978d6a81a84527fad03bc23861dbe28ab293f6 TimeStamp: 2013-05-14T20:22:37     NotificationEndPointId: nb:nepid:UUID:d6af9412-2488-45b2-ba1f-6e0ade6dbc27     State: Registered     Name: dde957b2-006e-41f2-9869-a978870ac620     Created: 2013-05-14T20:22:35  EventType: JobStateChange MessageVersion: 1.0 ETag: 4e381f37c2d844bde06ace650310284d6928b1e50101d82d1b56220cfcb6076c TimeStamp: 2013-05-14T20:24:40     JobId: nb:jid:UUID:526291de-f166-be47-b62a-11ffe6d4be54     JobName: My MP4 to Smooth Streaming encoding job     NewState: Finished     OldState: Processing     AccountName: westeuropewamsaccount job with Id: nb:jid:UUID:526291de-f166-be47-b62a-11ffe6d4be54 reached expected  State: Finished 

표시:
© 2014 Microsoft