private static async Task ProcessImageProcessingMessageAsync(ImageMessage message) { var stopwatch = new Stopwatch(); stopwatch.Start(); // keep track of the gallery id so we can work on the gallery after the message batch is processed lock (_galleryId) _galleryId = new DatabaseId(message.GalleryId, message.GalleryCategoryId); // retrieve Image object and bytes var image = await GetImageAsync(message.ImageId, message.GalleryId); var imageBytes = await GetImageBytesAsync(image); // create array of file specs to iterate over var specs = new List <FileSpec> { FileSpec.Spec3840, FileSpec.Spec2560, FileSpec.Spec1920, FileSpec.Spec800, FileSpec.SpecLowRes }; // resize original image file to smaller versions in parallel //var parallelTasks = specs.Select(spec => ProcessImageAsync(image, imageBytes, spec)).ToList(); //await Task.WhenAll(parallelTasks); //foreach (var spec in specs) // await ProcessImageAsync(image, imageBytes, spec); // This approach is the fastest of the three methods here. I have no idea why. // 20MB image resized five times (each spec) // Task.WhenAll: 11785ms average // Foreach: 8540ms average // Parallel.Foreach with GetAwaiter/GetResult: 7887ms average Parallel.ForEach(specs, spec => { ProcessImageAsync(image, imageBytes, spec).GetAwaiter().GetResult(); }); MetadataUtils.ParseAndAssignImageMetadata(image, imageBytes, message.OverwriteImageProperties, _log); await UpdateImageAsync(image); // pre-cache the image so it renders instantly for visitors PreCacheImage(image); // when uploading images, they don't have a position set, so if one is set when we process it here // then it's likely it's an existing Image that's having it's image file replaced. If so and the position // is zero then we want to make sure we update the gallery thumbnail to use the new image files. if (image.Position == 0) { _log.Debug("LB.PhotoGalleries.Worker.Program.ProcessImageProcessingMessageAsync() - Image position = 0, need to update gallery thumbnail..."); var gallery = await GetGalleryAsync(image.GalleryCategoryId, image.GalleryId); await UpdateGalleryThumbnailAsync(gallery, image.Files); } stopwatch.Stop(); _log.Information($"LB.PhotoGalleries.Worker.Program.ProcessImageProcessingMessageAsync() - Processed {image.Id} in {stopwatch.ElapsedMilliseconds}ms"); }
private static async Task HandleMessageAsync(QueueMessage message) { // decode the message var components = Utilities.Base64Decode(message.MessageText).Split(':'); ImageMessage imageMessage = null; try { imageMessage = new ImageMessage { Operation = Enum.Parse <WorkerOperation>(components[0], true), ImageId = components[1], GalleryId = components[2], GalleryCategoryId = components[3], OverwriteImageProperties = bool.Parse(components[4]) }; } catch (Exception e) { Log.Error($"LB.PhotoGalleries.Worker.Program.HandleMessageAsync() - Failed to decode message : '{message.MessageText}'", e); } try { if (imageMessage != null) { if (imageMessage.Operation == WorkerOperation.Process) { await ProcessImageProcessingMessageAsync(imageMessage); } else { await ReprocessImageMetadataAsync(imageMessage); } } } catch (ImageNotFoundException e) { _log.Error(e, "Image not found, deleting message."); } // as the message was processed successfully, we can delete the message from the queue await _queueClient.DeleteMessageAsync(message.MessageId, message.PopReceipt); }
/// <summary> /// Causes an image to have it's metadata re-examined and updates applied to the image. /// Useful for when we make improvements to metadata parsing. /// </summary> private static async Task ReprocessImageMetadataAsync(ImageMessage message) { // retrieve the image // download the bytes // parse the metadata // update the image properties // persist image changes to db _log.Verbose("LB.PhotoGalleries.Worker.Program.ReprocessImageMetadataAsync()"); var image = await GetImageAsync(message.ImageId, message.GalleryId); var imageBytes = await GetImageBytesAsync(image); MetadataUtils.ParseAndAssignImageMetadata(image, imageBytes, message.OverwriteImageProperties); await UpdateImageAsync(image); _log.Information($"LB.PhotoGalleries.Worker.Program.ReprocessImageMetadataAsync() - Reprocessed metadata on image {image.Id}"); }