Example #1
0
        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);
        }
Example #2
0
        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();
            }
        }
Example #3
0
        public static Task Run(string[] args)
        {
            var options = LoadTestSupervisorOptions.Parse(args);

            return(Run(options));
        }