Reputation: 8331
Our webapp will perform API calls to retrieve images. These images can be cached for a reasonable amount of time, as stated in the terms, so we don't have to hit up the other website's servers on every page request.
I am new to caching, but I just watched some Railscasts about some different methods. page caching
, fragment caching
, dynamic page caching
. They all help decrease the requests and therefor the speed of my app.
But how would I go by 'caching' images from another site on my servers? What is the correct way to do so? Are there any functions to serve this purpose?
would be to add a timestamp, cache_outdates_at
to my Image
model and set it one month into the future. Whenever the image get's loaded again it would update the timestamp.
Then I'd add a cronjob to check for outdated images and then delete them.
Upvotes: 4
Views: 2772
Reputation: 10018
I can share with you my own approach to cache external images on my side. Also, when I solve such task, I needed to update images on my side when underlying external image updated.
External service use e-tags for signing images, so I use this feature next way.
I have Photo
model which stores external_url
and etag
, as well as some info about image (image name for carrier wave in my case).
So, I have image_url
, received from some API, and I want to upload this image on my server, and don't want to load up external server.
photo = Photo.find_or_initialize_by(external_url: image_url)
img_responce = Faraday.get do |req|
req.url image_url
if photo.etag
req.headers['If-None-Match'] = photo.etag
end
end
case img_responce.status
when 200
# This mean, image changes (or new)
photo.update external_url: image_url,
etag: img_responce.headers['etag'],
image: StringIO.new(img_responce.body)
when 304
# This mean, image doesn't change
end
Upvotes: 0
Reputation: 8122
Nice Question. If you look the problem outside the box, it is fairly easy.
When you retrieve 3rd party server image, just copy that images and put it in your server or in CDN. And, use it. For this you have to setup some method something like
# app/model/image.rb
def image_link(name_of_image)
if File.exist? "/some/#{name_of_image}.jpg"
path = "/some/#{name_of_image}.jpg"
else
external_image_link = external_api_call(name_of_image)
DownloadImageWorker.perform_async(external_image_link) // perform it asynchronously
external_image_link
end
Upvotes: 3
Reputation: 917
I suggest that you not clutter your Rails application with code to cache off-site assets. Instead, use an HTTP proxy that is built for the job, such as Squid. Take a look at this example Squid configuration that caches off-site videos.
So, your webapp just needs to rewrite URLs, say, by appending cache.example.com
, or whatever the hostname of your caching server will be, to the URLs it generates. Set up a wildcard DNS entry so that *.cache.example.com
all point to your Squid server. Squid can be configured to rewrite the domain, fetch the remote asset, and serve it.
All of the cache management, including ejection of stale items, would be taken care of for you automatically by Squid. As a bonus, performance is likely to be better than on Rails.
Upvotes: 1