Nowadays Active Storage became go to solution for file storage for some projects based on Rails. So it works well as upload built-in tool, but how would you solve scaling issue when not using a cloud provider?
My storage.yaml content:
local:
service: Disk
root: <%= Rails.root.join("storage") %>
Let say I have rails1 and rails2 Docker containers with exactly the same Rails project and content in it.
Load balancer routes the requests to two containers using round-robin method.
1) Do you know whether Rails has something built-in to sort out high availability for local storage?
2) Is it possible to ensure that user uploads to only one Rails instance at the time? Then files can be one-way replicated.
3) If I managed to ensure that storage
directory is two-way replicated, is there any other location where Active Storage writes something except storage
data? cache, DB, etc. So at least I know that I need to focus only on storage
dir.
4) Do you recommend to create a separate file storage solution such as NFS (something similar to cloud) and mount onto both containers for read-write? How this solution would look like keeping in mind about simplicity?
Any other solutions would be great to know.
Many thanks
1, 2) I actually solved this at application level. ActiveStorage has a nice mechanism to get file location, url, size and other parameters. So when you know if something is missing on other instance, it can download from another instance or when something is uploaded on one instance, it can notify others to get the files. Not a must, but I used flock and thread to ensure that operation is unique and done in a background. I also considered "mirror", but official documentation stated that this is for backup purposes. Besides, I wanted to avoid external storage such as NFS, because you need to take of it's availability as well.
Some examples to start exploring this:
# Take first image
image = Ad.find(3770).images.first
# Get key
image_key = Ad.find(3770).images.first.key
# Get location on disk
image_location_on_disk = ActiveStorage::Blob.service.path_for(image_key)
# Include URL helper
include Rails.application.routes.url_helpers
# Get URL
url = Rails.application.routes.url_helpers.rails_blob_path(image, only_path: true)
# Get size
size = File.size?(image_location_on_disk)
# Check if file exists
size = File.exist?(image_location_on_disk)
3) No. It writes only to storage
directory and these files can be copied to another Rails instance so this is sufficient for another Rails instance to work.
4) I didn't test it by myself, but likely using NFS would solve the issue. In the other hand, you should ensure that NFS server is available. ActiveStorage creates unique files so the clash seems not possible if two instances write to the same storage.