public BulkImporter(CosmosDbConnectionString cosmosDbConnectionString) { _client = new DocumentClient( cosmosDbConnectionString.ServiceEndpoint, cosmosDbConnectionString.AuthKey, _connectionPolicy); }
/// <summary> /// Seeds the Cosmos DB metadata container. /// </summary> private static async Task SeedDatabase(CosmosDbConnectionString cosmosDbConnectionString, CancellationToken cancellationToken) { // Check if data exists before seeding. var count = 0; var query = new QueryDefinition($"SELECT VALUE COUNT(1) FROM c"); var container = await GetContainerIfExists(MetadataContainerName); var resultSetIterator = container.GetItemQueryIterator <int>(query, requestOptions: new QueryRequestOptions() { MaxItemCount = 1 }); if (resultSetIterator.HasMoreResults) { var result = await resultSetIterator.ReadNextAsync(); if (result.Count > 0) { count = result.FirstOrDefault(); } } if (count == 0) { // Scale up the requested throughput (RU/s) for the metadata container prior to bulk import: WriteLineInColor($"No data currently exists in the {MetadataContainerName} container. Scaling up the container RU/s to 50,000 prior to bulk data insert...", ConsoleColor.Cyan); await ChangeContainerPerformance(container, 50000); WriteLineInColor("Container RU/s adjusted. Generating data to seed database...", ConsoleColor.Cyan); var bulkImporter = new BulkImporter(cosmosDbConnectionString); var vehicles = DataGenerator.GenerateVehicles().ToList(); var consignments = DataGenerator.GenerateConsignments(900).ToList(); var packages = DataGenerator.GeneratePackages(consignments.ToList()).ToList(); var trips = DataGenerator.GenerateTrips(consignments.ToList(), vehicles.ToList()).ToList(); WriteLineInColor("Generated data to seed database. Saving metadata to Cosmos DB...", ConsoleColor.Cyan); // Save vehicles: WriteLineInColor($"Adding {vehicles.Count()} vehicles...", ConsoleColor.Green); await bulkImporter.BulkImport(vehicles, DatabaseName, MetadataContainerName, cancellationToken, 1); // Save consignments: WriteLineInColor($"Adding {consignments.Count()} consignments...", ConsoleColor.Green); await bulkImporter.BulkImport(consignments, DatabaseName, MetadataContainerName, cancellationToken, 1); // Save packages: WriteLineInColor($"Adding {packages.Count()} packages...", ConsoleColor.Green); await bulkImporter.BulkImport(packages, DatabaseName, MetadataContainerName, cancellationToken, 4); // Save trips: WriteLineInColor($"Adding {trips.Count()} trips...", ConsoleColor.Green); await bulkImporter.BulkImport(trips, DatabaseName, MetadataContainerName, cancellationToken, 1); WriteLineInColor("Finished seeding Cosmos DB.", ConsoleColor.Cyan); // Scale down the requested throughput (RU/s) for the metadata container: await ChangeContainerPerformance(container, 15000); } else { WriteLineInColor("\nCosmos DB already contains data. Skipping database seeding step...", ConsoleColor.Yellow); } }
static async Task Main(string[] args) { // Setup configuration to either read from the appsettings.json file (if present) or environment variables. var builder = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) .AddEnvironmentVariables(); _configuration = builder.Build(); var arguments = ParseArguments(); var cosmosDbConnectionString = new CosmosDbConnectionString(arguments.CosmosDbConnectionString); // Set an optional timeout for the generator. _cancellationSource = arguments.MillisecondsToRun == 0 ? new CancellationTokenSource() : new CancellationTokenSource(arguments.MillisecondsToRun); var cancellationToken = _cancellationSource.Token; var statistics = new Statistic[0]; List <Trip> trips; // Set the Cosmos DB connection policy. var connectionPolicy = new CosmosClientOptions { ConnectionMode = ConnectionMode.Direct }; var numberOfMillisecondsToLead = arguments.MillisecondsToLead; var taskWaitTime = 0; if (numberOfMillisecondsToLead > 0) { taskWaitTime = numberOfMillisecondsToLead; } var progress = new Progress <Progress>(); progress.ProgressChanged += (sender, progressArgs) => { foreach (var message in progressArgs.Messages) { WriteLineInColor(message.Message, message.Color.ToConsoleColor()); } statistics = progressArgs.Statistics; }; WriteLineInColor("Fleet Data Generator", ConsoleColor.White); Console.WriteLine(string.Empty); WriteLineInColor("Press Ctrl+C or Ctrl+Break to cancel.", ConsoleColor.Cyan); Console.WriteLine("Statistics for generated vehicle and related telemetry data will be updated for every 50 messages sent"); Console.WriteLine(string.Empty); Console.WriteLine("============="); WriteLineInColor("** Enter 1 to generate and send data for 1 vehicle.", ConsoleColor.Green); WriteLineInColor("** Enter 2 to generate and send data for 10 vehicles.", ConsoleColor.Green); WriteLineInColor("** Enter 3 to generate and send data for 50 vehicles.", ConsoleColor.Green); WriteLineInColor("** Enter 4 to generate and send data for 100 vehicles.", ConsoleColor.Green); WriteLineInColor("** Enter 5 to generate and send data for the number of vehicles defined in the application settings/environment variables.", ConsoleColor.Green); Console.WriteLine("============="); // Handle Control+C or Control+Break. Console.CancelKeyPress += (o, e) => { WriteLineInColor("Stopped generator. No more events are being sent.", ConsoleColor.Yellow); CancelAll(); // Allow the main thread to continue and exit... WaitHandle.Set(); }; var userInput = ""; var numberSimulatedTrucks = arguments.NumberSimulatedTrucks; var runGenerator = true; while (true) { Console.Write("Enter the number of the operation you would like to perform > "); var input = Console.ReadLine(); if (input != null && (input.Equals("1", StringComparison.InvariantCultureIgnoreCase) || input.Equals("2", StringComparison.InvariantCultureIgnoreCase) || input.Equals("3", StringComparison.InvariantCultureIgnoreCase) || input.Equals("4", StringComparison.InvariantCultureIgnoreCase) || input.Equals("5", StringComparison.InvariantCultureIgnoreCase))) { userInput = input.Trim(); break; } Console.WriteLine("Invalid input entered. Please enter either 1, 2, 3, 4, or 5."); } switch (userInput) { case "1": numberSimulatedTrucks = 1; break; case "2": numberSimulatedTrucks = 10; break; case "3": numberSimulatedTrucks = 50; break; case "4": numberSimulatedTrucks = 100; break; case "5": numberSimulatedTrucks = arguments.NumberSimulatedTrucks; break; default: // Exit. runGenerator = false; break; } if (runGenerator) { // Instantiate Cosmos DB client and start sending messages: using (_cosmosDbClient = new CosmosClient(cosmosDbConnectionString.ServiceEndpoint.OriginalString, cosmosDbConnectionString.AuthKey, connectionPolicy)) { await InitializeCosmosDb(); // Find and output the container details, including # of RU/s. var container = _database.GetContainer(MetadataContainerName); var offer = await container.ReadThroughputAsync(cancellationToken); if (offer != null) { var currentCollectionThroughput = offer ?? 0; WriteLineInColor( $"Found collection `{MetadataContainerName}` with {currentCollectionThroughput} RU/s.", ConsoleColor.Green); } // Ensure the telemetry container throughput is set to 15,000 RU/s. var telemetryContainer = await GetContainerIfExists(TelemetryContainerName); await ChangeContainerPerformance(telemetryContainer, 15000); // Initially seed the Cosmos DB database with metadata if empty. await SeedDatabase(cosmosDbConnectionString, cancellationToken); trips = await GetTripsFromDatabase(numberSimulatedTrucks, container); } try { // Start sending telemetry from simulated vehicles to Event Hubs: _runningVehicleTasks = await SetupVehicleTelemetryRunTasks(numberSimulatedTrucks, trips, arguments.IoTHubConnectionString); var tasks = _runningVehicleTasks.Select(t => t.Value).ToList(); while (tasks.Count > 0) { try { Task.WhenAll(tasks).Wait(cancellationToken); } catch (TaskCanceledException) { //expected } tasks = _runningVehicleTasks.Where(t => !t.Value.IsCompleted).Select(t => t.Value).ToList(); } } catch (OperationCanceledException) { Console.WriteLine("The vehicle telemetry operation was canceled."); // No need to throw, as this was expected. } CancelAll(); Console.WriteLine(); WriteLineInColor("Done sending generated vehicle telemetry data", ConsoleColor.Cyan); Console.WriteLine(); Console.WriteLine(); } // Keep the console open. Console.ReadLine(); WaitHandle.WaitOne(); }