/// <summary> /// Processes the customer. /// </summary> /// <param name="user">The AdWords user.</param> /// <param name="customerId">The customer ID.</param> /// <param name="query">The report query.</param> private void ProcessCustomer(AdWordsUser user, long customerId, string query) { // Set the customer ID to the current customer. this.Config.ClientCustomerId = customerId.ToString(); string downloadFile = string.Format("{0}{1}adgroup_{2:D10}.gz", this.DownloadFolder, Path.DirectorySeparatorChar, customerId); // Download the report. Console.WriteLine("[Thread #{0}]: Downloading report for customer: {1} into {2}...", this.ThreadIndex, customerId, downloadFile); try { ReportUtilities utilities = new ReportUtilities(user, "v201809", query, DownloadFormat.GZIPPED_CSV.ToString()); using (ReportResponse response = utilities.GetResponse()) { response.Save(downloadFile); } // Mark this report download as success. SuccessfulReportDownload success = new SuccessfulReportDownload { CustomerId = customerId, Path = downloadFile }; SuccessfulReports.TryAdd(success); Console.WriteLine("Report was downloaded to '{0}'.", downloadFile); } catch (AdWordsReportsException e) { // Mark this report download as failure. FailedReportDownload failure = new FailedReportDownload { CustomerId = customerId, Exception = e }; FailedReports.TryAdd(failure); Console.WriteLine( "Failed to download report for customer: {0}. Exception says {1}", customerId, e.Message); } }
/// <summary> /// Runs the code example. /// </summary> /// <param name="user">The AdWords user.</param> /// <param name="downloadFolder">The file to which the report is downloaded. /// </param> public void Run(AdWordsUser user, string downloadFolder) { // Increase the number of HTTP connections we can do in parallel. System.Net.ServicePointManager.DefaultConnectionLimit = 100; try { // Start the rate limiter with an initial value of zero, so that all // threads block immediately. Semaphore rateLimiter = new Semaphore(0, MAX_REPORT_DOWNLOADS_IN_PARALLEL); // Get all the advertiser accounts under this manager account. List <long> allCustomerIds = GetDescendantAdvertiserAccounts(user); // Create a concurrent queue of customers so that all threads can work // on the collection in parallel. ConcurrentQueue <long> customerQueue = new ConcurrentQueue <long>(allCustomerIds); // Create queues to keep track of successful and failed report downloads. ConcurrentQueue <SuccessfulReportDownload> reportsSucceeeded = new ConcurrentQueue <SuccessfulReportDownload>(); ConcurrentQueue <FailedReportDownload> reportsFailed = new ConcurrentQueue <FailedReportDownload>(); // Keep an array of events. This is used by the main thread to wait for // all worker threads to join. ManualResetEvent[] doneEvents = new ManualResetEvent[MAX_NUMBER_OF_THREADS]; // The list of threads to download reports. Thread[] threads = new Thread[MAX_NUMBER_OF_THREADS]; // The data for each thread. ReportDownloadData[] threadData = new ReportDownloadData[MAX_NUMBER_OF_THREADS]; // The query to be run on each account. string query = "SELECT CampaignId, AdGroupId, Impressions, Clicks, Cost from " + "ADGROUP_PERFORMANCE_REPORT where AdGroupStatus IN [ENABLED, PAUSED] " + "DURING LAST_7_DAYS"; // Initialize the threads and their data. for (int i = 0; i < MAX_NUMBER_OF_THREADS; i++) { doneEvents[i] = new ManualResetEvent(false); threadData[i] = new ReportDownloadData() { Config = (AdWordsAppConfig)(user.Config.Clone()), DownloadFolder = downloadFolder, SignalEvent = doneEvents[i], ThreadIndex = i, QuotaLock = rateLimiter, CustomerIdQueue = customerQueue, SuccessfulReports = reportsSucceeeded, FailedReports = reportsFailed }; threads[i] = new Thread(threadData[i].ThreadCallback); } // Start the threads. Since the initial value of rate limiter is zero, // all threads will block immediately. for (int i = 0; i < threads.Length; i++) { threads[i].Start(query); } // Now reset the rate limiter so all threads can start downloading reports. rateLimiter.Release(MAX_REPORT_DOWNLOADS_IN_PARALLEL); // Wait for all threads in pool to complete. WaitHandle.WaitAll(doneEvents); Console.WriteLine("Download completed, results:"); Console.WriteLine("Successful reports:"); while (!reportsSucceeeded.IsEmpty) { SuccessfulReportDownload success = null; if (reportsSucceeeded.TryDequeue(out success)) { Console.WriteLine("Client ID: {0}, Path: {1}", success.CustomerId, success.Path); } } Console.WriteLine("Failed reports:"); while (!reportsFailed.IsEmpty) { FailedReportDownload failure = null; if (reportsFailed.TryDequeue(out failure)) { Console.WriteLine("Client ID: {0}, Cause: {1}", failure.CustomerId, failure.Exception.Message); } } Console.WriteLine("All reports are downloaded."); } catch (Exception e) { throw new System.ApplicationException("Failed to download reports.", e); } }