public static LoadTestSupervisorOptions Parse(string[] args) { var builder = new ConfigurationBuilder(); builder.AddCommandLine(args); var config = builder.Build(); var configFileName = config.GetValue <string>(nameof(ConfigurationFileName), null); if (configFileName != null) { builder = new ConfigurationBuilder(); builder.AddJsonFile(configFileName, false); builder.AddCommandLine(args); } config = builder.Build(); var options = new LoadTestSupervisorOptions(); config.Bind(options); return(options); }
public static async Task Run(LoadTestSupervisorOptions options) { if (options == null) { throw new ArgumentNullException(nameof(options)); } var jobOutputDirectory = Path.Combine(options.OutputDirectory, $"loadtest-{options.Name}"); var logPath = Path.Combine(jobOutputDirectory, "supervisor-log.json"); ServicePointManager.DefaultConnectionLimit = options.Instances * 4; var formatter = new JsonFormatter(renderMessage: true, closingDelimiter: $",{Environment.NewLine}"); Log.Logger = new LoggerConfiguration() .WriteTo.LiterateConsole() .WriteTo.File(formatter, logPath) .Enrich.FromLogContext() .CreateLogger(); var logger = Log.Logger; var timeoutCts = new CancellationTokenSource(); try { logger.Information("Initialized with the following configuration: {@Configuration}", options); var creds = new BatchSharedKeyCredentials(options.BatchUrl, options.BatchAccountName, options.BatchAccountKey); using (var client = await BatchClient.OpenAsync(creds)) { logger.Information("Connected to Azure Batch service."); if (string.IsNullOrEmpty(options.ApplicationVersion)) { var latestVersion = await client.GetLatestApplicationVersion(); if (string.IsNullOrEmpty(latestVersion)) { throw new InvalidOperationException("Cannot determine load test application version."); } options.ApplicationVersion = latestVersion; } logger.Information("Will use load test v{Version}.", options.ApplicationVersion); if (!options.UseAutoPool) { var pool = await client.GetOrCreateLoadTestPool(options); await WaitForPoolToBeReady(pool); } var job = client.CreateLoadTestJob(options); await job.CommitAsync(cancellationToken : timeoutCts.Token); logger.Information("Created job: {JobId}.", job.Id); var tasks = Enumerable.Range(0, options.Instances) .Select(options.CreateLoadTestTask) .ToList(); await client.JobOperations.AddTaskAsync(job.Id, tasks); logger.Information("Added {TasksCount} tasks.", tasks.Count); job = client.JobOperations.GetJob(job.Id, new ODATADetailLevel(selectClause: "id")); job.OnAllTasksComplete = OnAllTasksComplete.TerminateJob; await job.CommitChangesAsync(cancellationToken : timeoutCts.Token); // Calculate run time from this moment timeoutCts.CancelAfter(options.JobTimeout.Add(10.Minutes())); var monitor = client.Utilities.CreateTaskStateMonitor(); tasks = await client .JobOperations .ListTasks(job.Id, new ODATADetailLevel(selectClause : "id")) .ToListAsync(timeoutCts.Token); await monitor.WhenAll(tasks, TaskState.Running, timeoutCts.Token); logger.Information("All tasks are {TaskState}.", TaskState.Running); var watchCts = new CancellationTokenSource(); WatchStatistics(logger, tasks, options.TaskStatisticsFetchInterval, watchCts.Token); await monitor.WhenAll(tasks, TaskState.Completed, timeoutCts.Token); watchCts.Cancel(); logger.Information("All tasks are {TaskState}.", TaskState.Completed); // ReSharper disable MethodSupportsCancellation foreach (var task in tasks) { await task.RefreshAsync(new ODATADetailLevel(selectClause : "id,executionInfo")); if (task.ExecutionInformation.SchedulingError != null) { logger.Error("Task {TaskId} completed with scheduling error: {@SchedulingError}.", task.Id, task.ExecutionInformation.SchedulingError); continue; } if (task.ExecutionInformation.ExitCode != 0) { logger.Error("Task {TaskId} exited with non-zero code.", task.Id); } } if (options.DownloadLogFiles) { await DownloadLogs(jobOutputDirectory, tasks, options.FileDownloadDegreeOfParallelism); } logger.Information("Load test complete."); } } catch (TaskCanceledException ex) { if (ex.CancellationToken == timeoutCts.Token) { logger.Error(ex, "Load test timeout."); } else { logger.Fatal(ex, "Load test failed: {ErrorMessage}", ex.Message); } throw; } catch (Exception ex) { logger.Fatal(ex, "Load test failed: {ErrorMessage}", ex.Message); throw; } finally { Log.CloseAndFlush(); } }
public static Task Run(string[] args) { var options = LoadTestSupervisorOptions.Parse(args); return(Run(options)); }