/// <summary> /// Get the certificates, if not from cache then from the server /// </summary> /// <param name="orderContexts"></param> /// <param name="runLevel"></param> /// <returns></returns> private async Task ExecuteOrders(List <OrderContext> orderContexts, RunLevel runLevel) { foreach (var order in orderContexts) { // Get the previously issued certificates in this renewal // sub order regardless of the fact that it may have another // shape (e.g. different SAN names or common name etc.). This // means we cannot use the cache key for it. order.PreviousCertificate = _certificateService. CachedInfos(order.Renewal, order.Order). OrderByDescending(x => x.Certificate.NotBefore). FirstOrDefault(); if (order.PreviousCertificate == null) { // Fallback to legacy cache file name without // order name part order.PreviousCertificate = _certificateService. CachedInfos(order.Renewal). Where(c => !orderContexts.Any(o => c.CacheFile !.Name.Contains($"-{o.Order.CacheKeyPart ?? "main"}-"))). OrderByDescending(x => x.Certificate.NotBefore). FirstOrDefault(); } // Get the existing certificate matching the order description // this may not be the same as the previous certificate order.NewCertificate = GetFromCache(order, runLevel); } // Group validations of multiple order together // as to maximize the potential gains in parallelization var fromServer = orderContexts.Where(x => x.NewCertificate == null).ToList(); foreach (var order in fromServer) { await CreateOrder(order); } // Validate all orders that need it var alwaysTryValidation = runLevel.HasFlag(RunLevel.Test) || runLevel.HasFlag(RunLevel.IgnoreCache); var validationRequired = fromServer.Where(x => x.Order.Details != null && (x.Order.Valid == false || alwaysTryValidation)); await _validator.AuthorizeOrders(validationRequired, runLevel); // Download all the orders in parallel await Task.WhenAll(orderContexts.Select(async order => { if (order.Result.Success == false) { _log.Verbose("Order {n}/{m} ({friendly}): validation error", orderContexts.IndexOf(order) + 1, orderContexts.Count, order.OrderName); } else if (order.NewCertificate == null) { _log.Verbose("Order {n}/{m} ({friendly}): processing...", orderContexts.IndexOf(order) + 1, orderContexts.Count, order.OrderName); order.NewCertificate = await GetFromServer(order); } else { _log.Verbose("Order {n}/{m} ({friendly}): handle from cache", orderContexts.IndexOf(order) + 1, orderContexts.Count, order.OrderName); } })); }