I am deploying Rails to Fly.io.
I have retrieved the stored image using ActiveStorage and created a download link using rails_blob_url for the blob data in the rails controller.
def show
image_url = rails_blob_url(@photo.image) if @photo.image.attached?
cropped_image_url = rails_blob_url(@photo.cropped_image) if @photo.cropped_image.attached?
render json: @photo.as_json.merge(image_url:, cropped_image_url:)
end
However, the download link I created failed to fetch about 5 out of 10 times. Also, it sometimes fails immediately after registration, but succeeds a few hours later.
Are you running multiple instances of your app? A volume is attached to a single machine, so the image is stored on just one volume. If a request hits another machine, the volume that’s attached to it won’t have the image.
This is the current setup status of Machine and Volume.
I have two Volumes set up and in use.
According to the rules of fly.io, at least two Volumes are required per App. If two Volumes are required, then two Machines are necessarily required.
Stop one Machine. Is that what you mean ?
❯ fly volumes list
ID STATE NAME SIZE REGION ZONE ENCRYPTED ATTACHED VM CREATED AT
vol_3q80vdxxxxxxxxxx created outdoor_heart_sutra_backend_data 1GB nrt a588 true 5683xxxxxxxxxx 2 days ago
vol_lgz1vppxxxxxxxxxx created outdoor_heart_sutra_backend_data 1GB nrt e73c true 148exxxxxxxxxx 2 days ago
❯ fly status
App
Name = outdoor-heart-sutra-backend
Owner = personal
Hostname = outdoor-heart-sutra-backend.fly.dev
Image = outdoor-heart-sutra-backend:deployment-01H2R2ADxxxxxxxxxxx
Platform = machines
Machines
PROCESS ID VERSION REGION STATE CHECKS LAST UPDATED
app 148exxxxxxxxxx 12 nrt started 2023-06-12T15:08:28Z
app 5683xxxxxxxxxx 12 nrt started 2023-06-12T15:10:42Z
I have two units running at all times.
However, setting up one unit to run does not solve the problem.
Not necessarily. If all machines in your app need to have access to uploaded files, you either need to replicate the data between volumes yourself or use something like S3 to store the data.
Volumes are local to machines by design. Data on a volume is persistent - it survives machines reboot, a volume can be detached and re-attached to a different machine with data intact - but only one machine can have access to a volume at any given time. So anything stored on a volume by machine A will only be available to machine A and not other machines.
However, setting up one unit to run does not solve the problem.
What is important is how you have configured Active Storage. Let’s start with the definition from the guide:
Active Storage facilitates uploading files to a cloud storage service like Amazon S3, Google Cloud Storage, or Microsoft Azure Storage and attaching those files to Active Record objects. It comes with a local disk-based service for development and testing and supports mirroring files to subordinate services for backups and migrations.
I highlighted the key words in that paragraph. So, skip over the disk storage configuration information in the guides and pick one of the other options.
Should I choose other storage options (Amazon S3, GCS, Microsoft Azure, ActiveStorage::PostgreSQL, MinIO) instead of using Volumes?
Is it not suitable for what I want to do? In other words, is it correct to say that using Volumes is not appropriate for importing external files and saving them to storage?
Rails clearly recommends Amazon S3, GCS, and Microsoft Azure for this purpose.
I know of two other alternatives, which I have mentioned.
If you want to use volumes, you will need to detect changes made on one machine and arrange for those changes to be made to all other machines. There are tools, like mirror that will do what you want, but I don’t know of anybody that has tried them on fly.io.
I see.
I would like to give up using Volume and use Amazon S3.
I would like to know for reference.
Does the system randomly determine which volume an image gets saved to if there are multiple volumes (say volumeA and volumeB)? For example, would it save the first image to volumeA and the second image to volumeB?
Are you running multiple instances of your app? A volume is attached to a single machine, so the image is stored on just one volume. If a request hits another machine, the volume that’s attached to it won’t have the image.
In response(@pavel ) to a previous comment, I would like to understand the concept of running multiple instances of an app. If I understand correctly, each instance is attached to a single volume. So does that mean if there are multiple images, there should be an equal number of instances? For instance, two instances for two images, three instances for three images, and so on?