The download link for image data retrieved from Volumes is invalid.

Hi, @rubys !!

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.

Is there any possibility of a volume cause?

# fly.toml

app = "outdoor-heart-sutra-backend"
primary_region = "nrt"
console_command = "/rails/bin/rails console"

[env]
  RAILS_STORAGE = "/mnt/volume/storage"

[http_service]
  internal_port = 3000
  force_https = true
  auto_stop_machines = true
  auto_start_machines = true
  min_machines_running = 2

[[statics]]
  guest_path = "/rails/public"
  url_prefix = "/"

[[mounts]]
  source = "outdoor_heart_sutra_backend_data"
  destination = "/mnt/volume"

Hi @shirotamaki

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.

Thank you for your reply.

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.

# fly.toml

min_machines_running = 2

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.

Can you elaborate on this?

Sure.

I will first explain the functionality of the application I am creating.

Tech Stack

  • Next.js 13.2.4
  • Rails 7.0.4 API Mode

Steps to import an image file and display it in the browser

  1. import image files (jpeg, png, heic)
  2. save blob data in a volume using ActiveStorage
  3. retrieve the saved blob data using ActiveStorage and create a download link using rails_blob_url
  4. call the download link in the front and display it in the browser

The following is the download link created in step 3.
The following download link is invalid.

2023-06-13T12:36:46.855 app[5683d3d0bd40d8] nrt [info] https://outdoor-heart-sutra-backend.fly.dev/rails/active_storage/blobs/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBUdz09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--5b1e1e68992fb90e834ec5cab5671c548d3413a9/blob.webp

2023-06-13T12:36:46.855 app[5683d3d0bd40d8] nrt [info] https://outdoor-heart-sutra-backend.fly.dev/rails/active_storage/blobs/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBVQT09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--94fddefc5d5183842ec0e901d5b1d8c312a5ec1b/croppedImage.webp

The following is successful creation of a successful download link.

2023-06-13T12:46:47.853 app[148ed5d5a3d668] nrt [info] https://outdoor-heart-sutra-backend.fly.dev/rails/active_storage/blobs/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBVUT09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--4099e04b4b944cb8b6830fce0eae988dde9c1974/2%E7%A9%BA.webp

2023-06-13T12:46:47.853 app[148ed5d5a3d668] nrt [info] https://outdoor-heart-sutra-backend.fly.dev/rails/active_storage/blobs/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBVZz09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--6c754428f90f0f3da1d173fb79d2afa542a728ed/croppedImage.webp

It succeeds about 5 out of 10 times.

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.

Two other options that you might want to explore GitHub - lsylvester/active_storage-postgresql: PostgreSQL Adapter for Active Storage and Deploy MinIO Object Storage to Fly.io · Fly Docs

More information here: Existing Rails Apps · Fly Docs

Thank you for reply.

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?

I try to avoid making recommendations.

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.

1 Like

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?

When load is low, incoming requests are routed randomly to machines within a region. Each machine will have a separate volume.

More details on load balancing within a region can be found here: Load balancing within a region - #2 by jerome

Thank you for the informative explanation.
I have summarized the relationship between Volume, App, and VM as follows:

Could you please confirm if my understanding is correct?

instance, VM, and machines are synonyms.

I would draw APP as encompassing both VMs on the left as well as the volumes. If you delete the app, all of those go away.

Similarly, I would draw DB as encompassing the remaining VM and volume.

A DB is just another app. It runs different code, but it can have multiple instances.

I would diagram it like this:

2 Likes

@rubys
Thank you very much for all your guidance. Your insights have greatly helped me understand the situation better.

@charsleysa
Thank you for diagram. It will be helpful.

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.