After having used a workaround sql fix-script for some time, I would like to implement a permanent fix for the following issue, but before creating a work item some guidance would be appreciated.
In a multi-node (multi-server) setup, a race condition exists when an image is generated from an image profile on 2 servers simultaneously (the issue is probably not limited to image generation, but simply much less likely to occur
Steps to reproduce
- Set up a site running on multiple nodes
- Create an image profile and use it somewhere
- Load the content with the image profile on 2 servers simultaneously
- A bit of luck (or rather, bad luck)
A duplicate record is not generated, instead the existing record is returned
Because the image profile is not cached locally on one of the servers, a duplicate record is inserted in Orchard_MediaProcessing_FileNameRecord, which in turn will cause an ArgumentException in ImageProcessingFileNameProvider.GetFileName() when the records
are loaded back into the local cache.
a) Now an obvious solution is sharing the cache between instances (for clarity: talking about Orchard.Caching.Cache NOT output or db cache)
- Unfortunately, I have started on implementing that using Redis, but there are too many objects being cached
which are not serializable.
Side-Note: Cause a bit of worldwide refactoring chaos and enforce serializable (json) on all objects and their descendants being cached?
b) Another solution is a unique constraint on Orchard_MediaProcessing_FileNameRecord.FileName and cause any attempt to insert a duplicate to crap out. This will generate one ugly exception, but at least not all images disappear from the site. Nevertheless,
this sounds like controlling flow with exceptions and an elephant in a china shop.
c) Instruct the data layer not to create duplicates, perhaps declaratively on a part's field, and instruct the data layer what to do when a record already exists: update, return existing, etc. (this can then be safely combined with a unique constraint at db