연습 - 앱에서 Azure Batch 진행률을 모니터링 및 기록하는 코드 추가

완료됨

Batch 클라이언트 API를 사용하면 앱에서 풀, 노드, 작업 및 태스크의 현재 상태를 모니터링할 수 있습니다.

회사의 콘솔 앱을 완료하여 비디오를 변환하려면 앱이 파일 변환 상태를 모니터링하고 보고하도록 해야 합니다. 또한 비디오가 변환되면 앱에서 작업과 풀을 삭제하는 기능을 추가하여 Batch 때문에 발생하는 비용을 줄여야 합니다. 파일 스토리지 비용을 줄이려면 업로드한 비디오 파일도 제거해야 합니다.

앱은 기존 풀을 확인하고, 풀이 없는 경우 해당 풀을 만듭니다. 작업과 태스크가 시작된 후 모니터링됩니다. 태스크가 성공적으로 완료되면 앱은 생성된 작업 및 풀을 삭제하는 옵션을 제공합니다. 앱은 Blob Storage 비용을 절감하기 위해 업로드된 비디오를 자동으로 삭제합니다.

모니터링 추가

  1. 다음과 같이 Cloud Shell에서 편집기를 사용하여 Program.cs 파일을 편집합니다.

    code Program.cs
    
  2. Program.cs에 작업 태스크를 모니터링하는 MonitorTasksAsync() 메서드를 추가합니다.

    private static async Task<bool> MonitorTasksAsync(BatchClient batchClient, string jobId, TimeSpan timeout)
    {
        bool allTasksSuccessful = true;
        const string completeMessage = "All tasks reached state Completed.";
        const string incompleteMessage = "One or more tasks failed to reach the Completed state within the timeout period.";
        const string successMessage = "Success! All tasks completed successfully. Output files uploaded to output container.";
        const string failureMessage = "One or more tasks failed.";
    
        Console.WriteLine("Monitoring all tasks for 'Completed' state, timeout in {0}...", timeout.ToString());
    
        // We use a TaskStateMonitor to monitor the state of our tasks. In this case, we will wait for all tasks to
        // reach the Completed state.
        IEnumerable<CloudTask> addedTasks = batchClient.JobOperations.ListTasks(JobId);
    
        TaskStateMonitor taskStateMonitor = batchClient.Utilities.CreateTaskStateMonitor();
        try
        {
            await taskStateMonitor.WhenAll(addedTasks, TaskState.Completed, timeout);
        }
        catch (TimeoutException)
        {
            await batchClient.JobOperations.TerminateJobAsync(jobId);
            Console.WriteLine(incompleteMessage);
            return false;
        }
        await batchClient.JobOperations.TerminateJobAsync(jobId);
        Console.WriteLine(completeMessage);
    
        // All tasks have reached the "Completed" state, however, this does not guarantee all tasks completed successfully.
        // Here we further check for any tasks with an execution result of "Failure".
    
        // Obtain the collection of tasks currently managed by the job. 
        // Use a detail level to specify that only the "id" property of each task should be populated. 
        // See https://learn.microsoft.com/azure/batch/batch-efficient-list-queries
        ODATADetailLevel detail = new ODATADetailLevel(selectClause: "executionInfo");
    
        // Filter for tasks with 'Failure' result.
        detail.FilterClause = "executionInfo/result eq 'Failure'";
    
        List<CloudTask> failedTasks = await batchClient.JobOperations.ListTasks(jobId, detail).ToListAsync();
    
        if (failedTasks.Any())
        {
            allTasksSuccessful = false;
            Console.WriteLine(failureMessage);
        }
        else
        {
            Console.WriteLine(successMessage);
        }
        return allTasksSuccessful;
    }
    

    TaskStateMonitor 개체가 호출되고, 모든 태스크의 상태가 (TaskState.Completed)이면 반환됩니다. 앱이 timeout 값보다 오래 기다려야 하는 경우 시간이 초과됩니다.

    이 메서드는 batchClient.JobOperations.ListTasks를 사용하여 Batch 계정에 있는 태스크의 현재 상태를 가져옵니다. ODATADetailLevel 매개 변수를 전달하여 필요한 정보만 반환하도록 이러한 호출을 필터링할 수 있습니다. 모든 태스크가 완료되면 코드에서 모든 작업이 성공적으로 완료되었는지 확인해야 하므로 ListTasks 호출에 "executionInfo/result eq 'Failure'" 필터를 사용하면 실패한 모든 작업이 반환됩니다.

  3. Main()의 using 블록 내부에 있는 새 MonitorTasksAsync() 메서드에 호출을 추가하고, AddTaskAsync 호출에서 반환된 태스크 목록을 저장합니다.

    using (BatchClient batchClient = BatchClient.Open(sharedKeyCredentials))
    {
        // Create the Batch pool, which contains the compute nodes that execute the tasks.
        await CreatePoolIfNotExistAsync(batchClient, PoolId);
    
        // Create the job that runs the tasks.
        await CreateJobAsync(batchClient, JobId, PoolId);
    
        // Create a collection of tasks and add them to the Batch job. 
        // Provide a shared access signature for the tasks so that they can upload their output
        // to the Storage container.
        List<CloudTask> runningTasks = await AddTasksAsync(batchClient, JobId, inputFiles, outputContainerSasUrl);
    
        // Monitor task success or failure, specifying a maximum amount of time to wait for
        // the tasks to complete.
        await MonitorTasksAsync(batchClient, JobId, TimeSpan.FromMinutes(30));
    }
    

정리

  1. using 블록 내에서 MonitorTasks 메서드 호출에 대한 호출 아래에 이 정리 코드를 추가합니다.

    // Delete input container in storage
    Console.WriteLine("Deleting container [{0}]...", inputContainerName);
    CloudBlobContainer container = blobClient.GetContainerReference(inputContainerName);
    await container.DeleteIfExistsAsync();
    
    // Clean up the job (if the user so chooses)
    Console.WriteLine();
    Console.Write("Delete job? [yes] no: ");
    string response = Console.ReadLine().ToLower();
    if (response != "n" && response != "no")
    {
        await batchClient.JobOperations.DeleteJobAsync(JobId);
    }
    
    // Clean up the pool (if the user so chooses - do not delete the pool if new batches of videos are ready to process)
    Console.Write("Delete pool? [yes] no: ");
    response = Console.ReadLine().ToLower();
    if (response != "n" && response != "no")
    {
        Console.WriteLine("Deleting pool ...");
        await batchClient.PoolOperations.DeletePoolAsync(PoolId);
        Console.WriteLine("Pool deleted.");
    }
    

    위의 코드는 업로드된 모든 비디오를 포함하는 입력 컨테이너를 삭제합니다.

    그런 다음 터미널에서 사용자에게 작업 및 풀을 삭제하도록 선택하라는 메시지를 표시합니다. batchClient을(를) 통해 앱에서 이러한 구성 요소를 삭제할 수 있습니다.

콘솔 앱 테스트

  1. 코드 편집기에서 마우스 오른쪽 단추를 클릭하고 저장을 선택한 다음 종료를 선택합니다.

  2. 앱을 빌드하고 실행합니다.

    dotnet run
    
  3. 다음과 유사한 출력이 표시됩니다.

    Creating container [input].
    Creating container [output].
    Uploading file ~\cutifypets\InputFiles\3.mp4 to container [input]...
    Uploading file ~\cutifypets\InputFiles\2.mp4 to container [input]...
    Uploading file ~\cutifypets\InputFiles\4.mp4 to container [input]...
    Uploading file ~\cutifypets\InputFiles\1.mp4 to container [input]...
    Uploading file ~\cutifypets\InputFiles\5.mp4 to container [input]...
    Uploading file ~\cutifypets\InputFiles\6.mp4 to container [input]...
    Creating pool [WinFFmpegPool]...
    Creating job [WinFFmpegJob]...
    Adding 6 tasks to job [WinFFmpegJob]...
    Monitoring all tasks for 'Completed' state, timeout in 00:30:00...
    All tasks reached state Completed.
    Success! All tasks completed successfully. Output files uploaded to output container.
    Deleting container [input]...
    
    Delete job? [yes] no: y
    Delete pool? [yes] no: y
    
    Sample complete, hit ENTER to exit...
    
  4. 그러나 이전 앱에 작업 정리 코드가 없으므로 이전 실행의 작업이 여전히 존재하는 경우 앱이 실패합니다. Azure Portal에서 또는 Cloud Shell에서 다음 명령으로 작업을 삭제할 수 있습니다.

    az batch job delete --job-id WinFFmpegJob \
    --account-name $BATCH_NAME \
    --account-key $BATCH_KEY \
    --account-endpoint $BATCH_URL
    
    Are you sure you want to perform this operation? (y/n):
    

    프롬프트에 y를 입력합니다.

  5. 이번에는 노드(Windows 2012를 실행하는 가상 머신 3대)가 유휴 상태로 작업이 실행되기를 기다리기 때문에 콘솔 앱이 훨씬 빠르게 실행됩니다.