/// <summary> /// Creates a scheduled job to archive /// </summary> /// <param name="mediaChannel"></param> /// <param name="archivalProgram"></param> /// <param name="jobName"></param> /// <returns></returns> private async Task <Microsoft.WindowsAzure.Scheduler.Models.JobCreateOrUpdateResponse> CreateScheduledJob(IChannel mediaChannel, IProgram archivalProgram, string jobName) { var cloudServiceName = NamingHelpers.GetSchedulerCloudServiceName(ServiceConfiguration.MediaServiceAccountName); var cloudServiceLabel = NamingHelpers.GetSchedulerCloudServiceLabel(ServiceConfiguration.MediaServiceAccountName); var cloudServiceDescription = NamingHelpers.GetSchedulerCloudServiceDescription(ServiceConfiguration.MediaServiceAccountName); var jobCollectionName = NamingHelpers.GetSchedulerJobCollectionName(ServiceConfiguration.MediaServiceAccountName); var cloudServiceRegion = ServiceConfiguration.SchedulerRegion; var bodyParameters = new SchedulerParameters { ChannelId = mediaChannel.Id, ProgramId = archivalProgram.Id, JobName = jobName }; var headers = new Dictionary <string, string>() { { "Content-Type", "application/json" }, }; var nextProgramJob = await SchedulerService.CreateOneTimeHttpJobAsync( cloudServiceName, jobCollectionName, jobName, DateTime.UtcNow.AddMinutes(ServiceConfiguration.ArchivalWindowMinutes).AddMinutes(-1 * ServiceConfiguration.OverlappingArchivalWindowMinutes), bodyParameters, headers, "POST", ServiceConfiguration.ScheduleManagerEndpoint); return(nextProgramJob); }
/// <summary> /// Prepares the scheduler /// </summary> /// <returns></returns> private async Task PrepareScheduler() { var cloudServiceName = NamingHelpers.GetSchedulerCloudServiceName(ServiceConfiguration.MediaServiceAccountName); var cloudServiceLabel = NamingHelpers.GetSchedulerCloudServiceLabel(ServiceConfiguration.MediaServiceAccountName); var cloudServiceDescription = NamingHelpers.GetSchedulerCloudServiceDescription(ServiceConfiguration.MediaServiceAccountName); var jobCollectionName = NamingHelpers.GetSchedulerJobCollectionName(ServiceConfiguration.MediaServiceAccountName); var cloudServiceRegion = ServiceConfiguration.SchedulerRegion; // Create Scheduler Service System.Diagnostics.Trace.TraceInformation("Preparing scheduler for Cloud Service [{0}], Job Collection[{1}]", cloudServiceName, jobCollectionName); var schedulerService = new SchedulerService(ServiceConfiguration); // Create Cloud Service for scheduler (if not exists, otheriwse, returns null) System.Diagnostics.Trace.TraceInformation("Creating Cloud Service for scheduler if it doesn't exist"); var cloudService = await schedulerService.CreateSchedulerCloudServiceIfNotExistsAsync(cloudServiceName, cloudServiceLabel, cloudServiceDescription, cloudServiceRegion); // Create a Job Collection (if not exists, otherwise, returns null) System.Diagnostics.Trace.TraceInformation("Creating Job Collection for scheduler if it doesn't exist"); var jobCollection = await schedulerService.CreateJobCollectionIfNotExistsAsync(cloudServiceName, jobCollectionName); }
// POST api/archives //[Authorize] public HttpResponseMessage Post(SchedulerParameters schedulerParameters) { System.Diagnostics.Trace.TraceInformation("Archiving requested for Channel ID [{0}], Program ID [{1}], Job Name [{2}]", schedulerParameters.ChannelId, schedulerParameters.ProgramId, schedulerParameters.JobName); // Fire and forget because otherwise, the scheduler will timeout after 30 seconds Task.Run(async() => { try { var cloudServiceName = NamingHelpers.GetSchedulerCloudServiceName(ServiceConfiguration.MediaServiceAccountName); var jobCollectionName = NamingHelpers.GetSchedulerJobCollectionName(ServiceConfiguration.MediaServiceAccountName); // Ensure that the scheduler is prepared await PrepareScheduler(); // Get the Channel by Channel Id var currentChannel = ChannelsService.GetChannel(schedulerParameters.ChannelId); System.Diagnostics.Trace.TraceInformation("Retrieved Channel [{0}] is {1}", schedulerParameters.ChannelId, currentChannel); // Update its cross domain access policy if needed ChannelsService.UpdateCrossSiteAccessPoliciesForChannelIfNeeded(currentChannel); // Identify what are we trying to do var runningPrograms = currentChannel.Programs.ToList().Where(p => p.State == Microsoft.WindowsAzure.MediaServices.Client.ProgramState.Running); var countOfRunningPrograms = runningPrograms.Count(); System.Diagnostics.Trace.TraceInformation("Channel [{0}] has [{1}] Running programs", schedulerParameters.ChannelId, countOfRunningPrograms); // If we have more than 2 programs (Default and Archival) running if (countOfRunningPrograms > 2) { // We are in an undefined state System.Diagnostics.Trace.TraceError("Channel [{0}] has [{1}] Running programs. This is an undefined state. Aborting.", schedulerParameters.ChannelId, countOfRunningPrograms); return; } // Now we got this out of the way // If we have no running programs if (countOfRunningPrograms == 0) { // Reset the channel try { System.Diagnostics.Trace.TraceError("Resetting Channel ID [{0}]"); await currentChannel.ResetAsync(); } catch (Exception ex) { System.Diagnostics.Trace.TraceError("Couldn't reset Channel ID [{0}]. \nException: {1}", currentChannel.Id, ex); } System.Diagnostics.Trace.TraceInformation("Starting DefaultProgram"); // Maybe we forgot to run the DefaultProgram from the portal, or deleted it // Start by creating the DefaultProgram then create the first ArchivalProgram and calling the scheduler var defaultProgram = await ChannelsService.CreateDefaultProgramIfNotExistsAsync(currentChannel, ServiceConfiguration.DefaultProgramArchivalWindowMinutes); } // Create an Archival Program System.Diagnostics.Trace.TraceInformation("Starting ArchivalProgram"); var archivalProgram = await ChannelsService.CreateArchivalProgramAsync(currentChannel, DateTime.UtcNow, ServiceConfiguration.ArchivalWindowMinutes, ServiceConfiguration.OverlappingArchivalWindowMinutes); var archivalJobName = NamingHelpers.GetArchivingJobName(currentChannel.Name); // Schedule the next job run System.Diagnostics.Trace.TraceInformation("Scheduling next job run"); var nextProgramJob = await CreateScheduledJob(currentChannel, archivalProgram, archivalJobName); // If we had 2 running programs, then we are trying to schedule the follow-up and toggle the archives if (nextProgramJob != null && countOfRunningPrograms == 2) { System.Diagnostics.Trace.TraceInformation("We had 2 running programs, then we are trying to schedule the follow-up and toggle the archives"); // Stop the current (old) program // Get the Program by Program Id System.Diagnostics.Trace.TraceInformation("Getting current program [{0}]", schedulerParameters.ProgramId); var currentProgram = ChannelsService.GetProgram(schedulerParameters.ProgramId); // Stop it System.Diagnostics.Trace.TraceInformation("Stopping current program [{0}]", schedulerParameters.ProgramId); await currentProgram.StopAsync(); System.Diagnostics.Trace.TraceInformation("Stopped [{0}]", schedulerParameters.ProgramId); } } catch (Exception ex) { System.Diagnostics.Trace.TraceError("Exception: {0}\n", ex); } }); return(Request.CreateResponse(HttpStatusCode.OK)); }