예제 #1
0
        private static async Task MainAsync()
        {
            string poolId = "JobPrepReleaseSamplePool";
            string jobId  = "JobPrepReleaseSampleJob";

            var settings = Config.LoadAccountSettings();

            // Location of the file that the job tasks will work with, a text file in the
            // node's "shared" directory.
            string taskOutputFile = "$AZ_BATCH_NODE_SHARED_DIR/job_prep_and_release.txt";

            // The job prep task will write the node ID to the text file in the shared directory
            string jobPrepCmdLine = $@"/bin/bash -c ""echo $AZ_BATCH_NODE_ID tasks: > {taskOutputFile}""";

            // Each task then echoes its ID to the same text file
            string taskCmdLine = $@"/bin/bash -c ""echo $AZ_BATCH_TASK_ID >> {taskOutputFile}""";

            // The job release task will then delete the text file from the shared directory
            string jobReleaseCmdLine = $@"/bin/bash -c ""rm {taskOutputFile}""";

            BatchSharedKeyCredentials cred = new BatchSharedKeyCredentials(settings.BatchServiceUrl, settings.BatchAccountName, settings.BatchAccountKey);

            using (BatchClient batchClient = BatchClient.Open(cred))
            {
                var pool = await BatchUtils.CreatePoolIfNotExistAsync(batchClient, poolId);

                var prepTask = new JobPreparationTask {
                    CommandLine = jobPrepCmdLine
                };
                var releaseTask = new JobReleaseTask {
                    CommandLine = jobReleaseCmdLine
                };

                var job = await BatchUtils.CreateJobIfNotExistAsync(batchClient, pool.Id, jobId, prepTask : prepTask, releaseTask : releaseTask);

                // Create the tasks that the job will execute
                List <CloudTask> tasks = new List <CloudTask>();
                for (int i = 1; i <= 8; i++)
                {
                    string    taskId          = "task" + i.ToString().PadLeft(3, '0');
                    string    taskCommandLine = taskCmdLine;
                    CloudTask task            = new CloudTask(taskId, taskCommandLine);
                    tasks.Add(task);
                }

                // Add the tasks in one API call as opposed to a separate AddTask call for each. Bulk task
                // submission helps to ensure efficient underlying API calls to the Batch service.
                Console.WriteLine("Submitting tasks and awaiting completion...");
                await batchClient.JobOperations.AddTaskAsync(job.Id, tasks);

                // Wait for the tasks to complete before proceeding. The long timeout here is to allow time
                // for the nodes within the pool to be created and started if the pool had not yet been created.
                await batchClient.Utilities.CreateTaskStateMonitor().WhenAll(
                    job.ListTasks(),
                    TaskState.Completed,
                    TimeSpan.FromMinutes(30));

                Console.WriteLine("All tasks completed.");
                Console.WriteLine();

                // Print the contents of the shared text file modified by the job preparation and other tasks.
                ODATADetailLevel nodeDetail          = new ODATADetailLevel(selectClause: "id, state");
                IPagedEnumerable <ComputeNode> nodes = batchClient.PoolOperations.ListComputeNodes(poolId, nodeDetail);
                await nodes.ForEachAsync(async (node) =>
                {
                    // Check to ensure that the node is Idle before attempting to pull the text file.
                    // If the pool was just created, there is a chance that another node completed all
                    // of the tasks prior to the other node(s) completing their startup procedure.
                    if (node.State == ComputeNodeState.Idle)
                    {
                        var files = await node.ListNodeFiles().ToListAsync();
                        NodeFile sharedTextFile = await node.GetNodeFileAsync("shared/job_prep_and_release.txt");
                        Console.WriteLine("Contents of {0} on {1}:", sharedTextFile.Path, node.Id);
                        Console.WriteLine("-------------------------------------------");
                        Console.WriteLine(await sharedTextFile.ReadAsStringAsync());
                    }
                });

                // Terminate the job to mark it as Completed; this will initiate the Job Release Task on any node
                // that executed job tasks. Note that the Job Release Task is also executed when a job is deleted,
                // thus you need not call Terminate if you typically delete your jobs upon task completion.
                await batchClient.JobOperations.TerminateJobAsync(job.Id);

                // Wait for the job to reach state "Completed." Note that this wait is not typically necessary in
                // production code, but is done here to enable the checking of the release tasks exit code below.
                await BatchUtils.WaitForJobToReachStateAsync(batchClient, job.Id, JobState.Completed, TimeSpan.FromMinutes(2));

                // Print the exit codes of the prep and release tasks by obtaining their execution info
                List <JobPreparationAndReleaseTaskExecutionInformation> prepReleaseInfo = await batchClient.JobOperations.ListJobPreparationAndReleaseTaskStatus(job.Id).ToListAsync();

                foreach (JobPreparationAndReleaseTaskExecutionInformation info in prepReleaseInfo)
                {
                    Console.WriteLine();
                    Console.WriteLine("{0}: ", info.ComputeNodeId);

                    // If no tasks were scheduled to run on the node, the JobPreparationTaskExecutionInformation will be null
                    if (info.JobPreparationTaskExecutionInformation != null)
                    {
                        Console.WriteLine("  Prep task exit code:    {0}", info.JobPreparationTaskExecutionInformation.ExitCode);
                    }

                    // If no tasks were scheduled to run on the node, the JobReleaseTaskExecutionInformation will be null
                    if (info.JobReleaseTaskExecutionInformation != null)
                    {
                        Console.WriteLine("  Release task exit code: {0}", info.JobReleaseTaskExecutionInformation.ExitCode);
                    }
                }

                // Clean up the resources we've created in the Batch account
                Console.WriteLine();
                Console.WriteLine("Delete job? [yes] no");
                string response = Console.ReadLine().ToLower();
                if (response != "n" && response != "no")
                {
                    // Note that deleting the job will execute the job release task if the job was not previously terminated
                    await batchClient.JobOperations.DeleteJobAsync(job.Id);
                }

                Console.WriteLine("Delete pool? [yes] no");
                response = Console.ReadLine();
                if (response != "n" && response != "no")
                {
                    await batchClient.PoolOperations.DeletePoolAsync(poolId);
                }
            }
        }
예제 #2
0
        private static async Task MainAsync()
        {
            //const string nodeSize = "standard_a1_v2";
            const string nodeSize        = "standard_a4_v2";
            const int    nodeCount       = 4;
            const int    maxTasksPerNode = 4; //can be set to 4* the number of cores on each node
            const int    taskCount       = 32;

            // Ensure there are enough tasks to help avoid hitting some timeout conditions below
            int minimumTaskCount = nodeCount * maxTasksPerNode * 2;

            if (taskCount < minimumTaskCount)
            {
                Console.WriteLine("You must specify at least two tasks per node core for this sample ({0} tasks in this configuration).", minimumTaskCount);
                Console.WriteLine();

                // Not enough tasks, exit the application
                return;
            }

            // In this sample, the tasks simply ping localhost on the compute nodes; adjust these
            // values to simulate variable task duration
            const int minPings = 30;
            const int maxPings = 60;

            const string poolId = "ParallelTasksPoolDemo";
            const string jobId  = "ParallelTasksJob";

            var settings = Config.LoadAccountSettings();

            BatchSharedKeyCredentials cred = new BatchSharedKeyCredentials(settings.BatchServiceUrl, settings.BatchAccountName, settings.BatchAccountKey);

            using (BatchClient batchClient = BatchClient.Open(cred))
            {
                var pool = await BatchUtils.CreatePoolIfNotExistAsync(
                    batchClient,
                    poolId,
                    nodeSize : nodeSize,
                    maxTasksPerNode : maxTasksPerNode,
                    schedulingPolicy : new TaskSchedulingPolicy(ComputeNodeFillType.Pack),
                    lowPriorityNodes : nodeCount);

                CloudJob job = await BatchUtils.CreateJobIfNotExistAsync(batchClient, poolId, jobId);

                // The job's tasks ping localhost a random number of times between minPings and maxPings.
                // Adjust the minPings/maxPings values above to experiment with different task durations.
                Random           rand  = new Random();
                List <CloudTask> tasks = new List <CloudTask>();
                for (int i = 1; i <= taskCount; i++)
                {
                    string    taskId          = "task" + i.ToString().PadLeft(3, '0');
                    string    taskCommandLine = "ping -c " + rand.Next(minPings, maxPings + 1).ToString() + " localhost";
                    CloudTask task            = new CloudTask(taskId, taskCommandLine);
                    tasks.Add(task);
                }

                // Pause execution until the pool is steady and its compute nodes are ready to accept jobs.
                // NOTE: Such a pause is not necessary within your own code. Tasks can be added to a job at any point and will be
                // scheduled to execute on a compute node as soon any node has reached Idle state. Because the focus of this sample
                // is the demonstration of running tasks in parallel on multiple compute nodes, we wait for all compute nodes to
                // complete initialization and reach the Idle state in order to maximize the number of compute nodes available for
                // parallelization.
                await BatchUtils.WaitForPoolToReachStateAsync(batchClient, poolId, AllocationState.Steady, TimeSpan.FromMinutes(30));

                await BatchUtils.WaitForNodesToReachStateAsync(batchClient, poolId, ComputeNodeState.Idle, TimeSpan.FromMinutes(30));


                // Add the tasks in one API call as opposed to a separate AddTask call for each. Bulk task
                // submission helps to ensure efficient underlying API calls to the Batch service.
                Console.WriteLine("Submitting tasks and awaiting completion...");
                await batchClient.JobOperations.AddTaskAsync(job.Id, tasks);

                // Pause again to wait until *all* nodes are running tasks
                await BatchUtils.WaitForNodesToReachStateAsync(batchClient, poolId, ComputeNodeState.Running, TimeSpan.FromMinutes(2));

                Stopwatch stopwatch = Stopwatch.StartNew();

                // Print out task assignment information.
                Console.WriteLine();
                await BatchUtils.PrintNodeTasksAsync(batchClient, poolId);

                Console.WriteLine();

                // Pause execution while we wait for all of the tasks to complete
                Console.WriteLine("Waiting for task completion...");
                Console.WriteLine();

                try
                {
                    await batchClient.Utilities.CreateTaskStateMonitor().WhenAll(
                        job.ListTasks(),
                        TaskState.Completed,
                        TimeSpan.FromMinutes(30));
                }
                catch (TimeoutException e)
                {
                    Console.WriteLine(e.ToString());
                }

                stopwatch.Stop();

                // Obtain the tasks, specifying a detail level to limit the number of properties returned for each task.
                // If you have a large number of tasks, specifying a DetailLevel is extremely important in reducing the
                // amount of data transferred, lowering your query response times in increasing performance.
                ODATADetailLevel             detail   = new ODATADetailLevel(selectClause: "id,commandLine,nodeInfo,state");
                IPagedEnumerable <CloudTask> allTasks = batchClient.JobOperations.ListTasks(job.Id, detail);

                // Get a collection of the completed tasks sorted by the compute nodes on which they executed
                List <CloudTask> completedTasks = allTasks
                                                  .Where(t => t.State == TaskState.Completed)
                                                  .OrderBy(t => t.ComputeNodeInformation.ComputeNodeId)
                                                  .ToList();

                // Print the completed task information
                Console.WriteLine();
                Console.WriteLine("Completed tasks:");
                string lastNodeId = string.Empty;
                foreach (CloudTask task in completedTasks)
                {
                    if (!string.Equals(lastNodeId, task.ComputeNodeInformation.ComputeNodeId))
                    {
                        Console.WriteLine();
                        Console.WriteLine(task.ComputeNodeInformation.ComputeNodeId);
                    }

                    lastNodeId = task.ComputeNodeInformation.ComputeNodeId;

                    Console.WriteLine("\t{0}: {1}", task.Id, task.CommandLine);
                }

                // Get a collection of the uncompleted tasks which may exist if the TaskMonitor timeout was hit
                List <CloudTask> uncompletedTasks = allTasks
                                                    .Where(t => t.State != TaskState.Completed)
                                                    .OrderBy(t => t.Id)
                                                    .ToList();

                // Print a list of uncompleted tasks, if any
                Console.WriteLine();
                Console.WriteLine("Uncompleted tasks:");
                Console.WriteLine();
                if (uncompletedTasks.Any())
                {
                    foreach (CloudTask task in uncompletedTasks)
                    {
                        Console.WriteLine("\t{0}: {1}", task.Id, task.CommandLine);
                    }
                }
                else
                {
                    Console.WriteLine("\t<none>");
                }

                // Print some summary information
                Console.WriteLine();
                Console.WriteLine("             Nodes: " + nodeCount);
                Console.WriteLine("         Node size: " + nodeSize);
                Console.WriteLine("Max tasks per node: " + pool.MaxTasksPerComputeNode);
                Console.WriteLine("             Tasks: " + tasks.Count);
                Console.WriteLine("          Duration: " + stopwatch.Elapsed);
                Console.WriteLine();
                Console.WriteLine("Done!");
                Console.WriteLine();

                // Clean up the resources we've created in the Batch account
                Console.WriteLine();
                Console.WriteLine("Delete job? [yes] no");
                string response = Console.ReadLine().ToLower();
                if (response != "n" && response != "no")
                {
                    // Note that deleting the job will execute the job release task if the job was not previously terminated
                    await batchClient.JobOperations.DeleteJobAsync(job.Id);
                }

                Console.WriteLine("Delete pool? [yes] no");
                response = Console.ReadLine();
                if (response != "n" && response != "no")
                {
                    await batchClient.PoolOperations.DeletePoolAsync(poolId);
                }
            }
        }
예제 #3
0
        private static async Task MainAsync()
        {
            const string poolId = "FileHandlingPool";
            const string jobId  = "FileHandlingJobDemo";

            var settings = Config.LoadAccountSettings();

            SetupStorage(settings.StorageAccountName, settings.StorageAccountKey);

            BatchSharedKeyCredentials cred = new BatchSharedKeyCredentials(settings.BatchServiceUrl, settings.BatchAccountName, settings.BatchAccountKey);

            using (BatchClient batchClient = BatchClient.Open(cred))
            {
                var pool = await BatchUtils.CreatePoolIfNotExistAsync(batchClient, poolId);

                var job = await BatchUtils.CreateJobIfNotExistAsync(batchClient, poolId, jobId);

                //set up auto storage file
                ResourceFile autoStorageFile = ResourceFile.FromAutoStorageContainer(AutoStorageContainerName, AutoStorageFileName);
                Console.WriteLine("\n[INFO] Autostorage resource File reference: ");
                Console.WriteLine("AutoStorageContainer: " + autoStorageFile.AutoStorageContainerName);
                Console.WriteLine("FilePath: " + autoStorageFile.FilePath);

                //upload file to external storage and add it as a resource file
                string storageConnectionString =
                    $"DefaultEndpointsProtocol=https;AccountName={settings.StorageAccountName};AccountKey={settings.StorageAccountKey}";

                CloudStorageAccount storageAccount    = CloudStorageAccount.Parse(storageConnectionString);
                CloudBlobClient     blobClient        = storageAccount.CreateCloudBlobClient();
                CloudBlobContainer  externalContainer = blobClient.GetContainerReference(ExternalStorageContainerName);
                await externalContainer.CreateIfNotExistsAsync();

                var externalFile = await UploadFileToContainer(blobClient, ExternalStorageContainerName, "resource_files/resource_file.txt", "resource_file.txt");

                Console.WriteLine("\n[INFO] External storage resource File reference:");
                Console.WriteLine("SAS Url: " + externalFile.HttpUrl);
                Console.WriteLine("FilePath: " + externalFile.FilePath);


                // using staging files API
                var filesToStage = new List <IFileStagingProvider>();
                StagingStorageAccount fileStagingStorageAccount = new StagingStorageAccount(
                    storageAccount: settings.StorageAccountName,
                    storageAccountKey: settings.StorageAccountKey,
                    blobEndpoint: storageAccount.BlobEndpoint.ToString());

                FileToStage stagedFile = new FileToStage("resource_files/staged_file.txt", fileStagingStorageAccount);
                Console.WriteLine("\n[INFO] Staged File added:");
                Console.WriteLine("Local File: " + stagedFile.LocalFileToStage);
                Console.WriteLine("Node File: " + stagedFile.NodeFileName);

                filesToStage.Add(stagedFile);

                // setup output files
                // Generate SAS for outputcontainer
                CloudBlobContainer outputContainer = blobClient.GetContainerReference(OutputContainerName);
                await outputContainer.CreateIfNotExistsAsync();

                string containerSas = outputContainer.GetSharedAccessSignature(new SharedAccessBlobPolicy()
                {
                    Permissions            = SharedAccessBlobPermissions.Write,
                    SharedAccessExpiryTime = DateTimeOffset.UtcNow.AddDays(1)
                });
                string containerUrl = outputContainer.Uri.AbsoluteUri + containerSas;
                Console.WriteLine("\n[INFO] Output container: " + containerUrl);

                Console.WriteLine("\nPress return to continue...");
                Console.ReadLine();

                // Create tasks
                List <CloudTask> tasks = new List <CloudTask>();

                for (var i = 1; i <= 10; i++)
                {
                    var taskId      = i.ToString().PadLeft(3, '0');
                    var commandLine = $@"/bin/bash -c ""echo 'Hello from {taskId}' && printf 'root dir:\n' > output.txt && ls -la >> output.txt && printf '\ninput dir:\n' >> output.txt && ls -la input >> output.txt""";
                    var task        = new CloudTask(taskId, commandLine);

                    // add resource files to task (one autostorage, one in external storage)
                    task.ResourceFiles = new[] { autoStorageFile, externalFile };

                    // add staged files
                    task.FilesToStage = filesToStage;

                    // add output files
                    var outputFiles = new List <OutputFile>
                    {
                        new OutputFile(
                            filePattern: @"../std*.txt",
                            destination: new OutputFileDestination(new OutputFileBlobContainerDestination(
                                                                       containerUrl: containerUrl,
                                                                       path: taskId)),
                            uploadOptions: new OutputFileUploadOptions(
                                uploadCondition: OutputFileUploadCondition.TaskCompletion)),
                        new OutputFile(
                            filePattern: @"output.txt",
                            destination: new OutputFileDestination(new OutputFileBlobContainerDestination(
                                                                       containerUrl: containerUrl,
                                                                       path: taskId + @"\output.txt")),
                            uploadOptions: new OutputFileUploadOptions(
                                uploadCondition: OutputFileUploadCondition.TaskCompletion)),
                    };

                    task.OutputFiles = outputFiles;

                    tasks.Add(task);
                }

                Console.WriteLine("Submitting tasks and awaiting completion...");
                // Add all tasks to the job.
                batchClient.JobOperations.AddTask(job.Id, tasks);

                await BatchUtils.WaitForTasksAndPrintOutputAsync(batchClient, job.ListTasks(), TimeSpan.FromMinutes(30));

                // Clean up Batch resources (if the user so chooses)
                Console.WriteLine();
                Console.Write("Delete job? [yes] no: ");
                string response = Console.ReadLine().ToLower();
                if (response != "n" && response != "no")
                {
                    batchClient.JobOperations.DeleteJob(jobId);
                }

                Console.Write("Delete pool? [yes] no: ");
                response = Console.ReadLine().ToLower();
                if (response != "n" && response != "no")
                {
                    batchClient.PoolOperations.DeletePool(poolId);
                }
            }
        }
예제 #4
0
        private static async Task MainAsync()
        {
            const int nodeCount = 1;

            string poolId = "TaskDependenciesSamplePool";
            string jobId  = "TaskDependenciesJob";

            var settings = Config.LoadAccountSettings();

            BatchSharedKeyCredentials cred = new BatchSharedKeyCredentials(settings.BatchServiceUrl, settings.BatchAccountName, settings.BatchAccountKey);

            using (BatchClient batchClient = BatchClient.Open(cred))
            {
                var pool = await BatchUtils.CreatePoolIfNotExistAsync(batchClient, poolId, lowPriorityNodes : nodeCount);

                var job = await BatchUtils.CreateJobIfNotExistAsync(batchClient, pool.Id, jobId, usesTaskDependencies : true);

                string taskOutputFile = "$AZ_BATCH_NODE_SHARED_DIR/task_output.txt";

                // Create the collection of tasks that will be added to the job.
                List <CloudTask> tasks = new List <CloudTask>
                {
                    // 'Rain' and 'Sun' don't depend on any other tasks
                    new CloudTask("Rain", $"/bin/bash -c \"echo Rain >> {taskOutputFile}\""),
                    new CloudTask("Sun", $"/bin/bash -c \"echo Sun >> {taskOutputFile}\""),

                    // Task 'Flowers' depends on completion of both 'Rain' and 'Sun'
                    // before it is run.
                    new CloudTask("Flowers", $"/bin/bash -c \"echo Flowers >> {taskOutputFile}\"")
                    {
                        DependsOn = TaskDependencies.OnIds("Rain", "Sun")
                    },

                    // Tasks 1, 2, and 3 don't depend on any other tasks. Because
                    // we will be using them for a task range dependency, we must
                    // specify string representations of integers as their ids.
                    new CloudTask("1", $"/bin/bash -c \"echo 1  >> {taskOutputFile}\""),
                    new CloudTask("2", $"/bin/bash -c \"echo 2  >> {taskOutputFile}\""),
                    new CloudTask("3", $"/bin/bash -c \"echo 3  >> {taskOutputFile}\""),

                    // Task dependency on ID range
                    new CloudTask("Final", $"/bin/bash -c \"echo Final >> {taskOutputFile}\"")
                    {
                        DependsOn = TaskDependencies.OnIdRange(1, 3)
                    },

                    // Task A is the parent task.
                    new CloudTask("A", $"/bin/bash -c \"echo A  >> {taskOutputFile}\"")
                    {
                        // Specify exit conditions for task A and their dependency actions.
                        ExitConditions = new ExitConditions
                        {
                            // If task A exits with a pre-processing error, block any downstream tasks (in this example, task B).
                            PreProcessingError = new ExitOptions
                            {
                                DependencyAction = DependencyAction.Block
                            },
                            // If task A exits with the specified error codes, block any downstream tasks (in this example, task B).
                            ExitCodes = new List <ExitCodeMapping>
                            {
                                new ExitCodeMapping(10, new ExitOptions()
                                {
                                    DependencyAction = DependencyAction.Block
                                }),
                                new ExitCodeMapping(20, new ExitOptions()
                                {
                                    DependencyAction = DependencyAction.Block
                                })
                            },
                            // If task A succeeds or fails with any other error, any downstream tasks become eligible to run
                            // (in this example, task B).
                            Default = new ExitOptions
                            {
                                DependencyAction = DependencyAction.Satisfy
                            },
                        }
                    },
                    // Task B depends on task A. Whether it becomes eligible to run depends on how task A exits.
                    new CloudTask("B", $"/bin/bash -c \"echo B  >> {taskOutputFile}\"")
                    {
                        DependsOn = TaskDependencies.OnId("A")
                    },
                };
                // Add the tasks in one API call as opposed to a separate AddTask call for each. Bulk task
                // submission helps to ensure efficient underlying API calls to the Batch service.
                Console.WriteLine("Submitting tasks and awaiting completion...");
                await batchClient.JobOperations.AddTaskAsync(job.Id, tasks);

                // Wait for the tasks to complete before proceeding. The long timeout here is to allow time
                // for the nodes within the pool to be created and started if the pool had not yet been created.
                await batchClient.Utilities.CreateTaskStateMonitor().WhenAll(
                    job.ListTasks(),
                    TaskState.Completed,
                    TimeSpan.FromMinutes(30));

                Console.WriteLine("All tasks completed.");
                Console.WriteLine();

                // Print the contents of the shared text file modified by the job preparation and other tasks.
                ODATADetailLevel nodeDetail          = new ODATADetailLevel(selectClause: "id, state");
                IPagedEnumerable <ComputeNode> nodes = batchClient.PoolOperations.ListComputeNodes(poolId, nodeDetail);
                await nodes.ForEachAsync(async (node) =>
                {
                    // Check to ensure that the node is Idle before attempting to pull the text file.
                    // If the pool was just created, there is a chance that another node completed all
                    // of the tasks prior to the other node(s) completing their startup procedure.
                    if (node.State == ComputeNodeState.Idle)
                    {
                        NodeFile sharedTextFile = await node.GetNodeFileAsync("shared/task_output.txt");
                        Console.WriteLine("Contents of {0} on {1}:", sharedTextFile.Path, node.Id);
                        Console.WriteLine("-------------------------------------------");
                        Console.WriteLine(await sharedTextFile.ReadAsStringAsync());
                    }
                });

                // Clean up the resources we've created in the Batch account
                Console.WriteLine();
                Console.WriteLine("Delete job? [yes] no");
                string response = Console.ReadLine().ToLower();
                if (response != "n" && response != "no")
                {
                    // Note that deleting the job will execute the job release task if the job was not previously terminated
                    await batchClient.JobOperations.DeleteJobAsync(job.Id);
                }

                Console.WriteLine("Delete pool? [yes] no");
                response = Console.ReadLine();
                if (response != "n" && response != "no")
                {
                    await batchClient.PoolOperations.DeletePoolAsync(poolId);
                }
            }
        }