choonkeat / attache

Yet another approach to file upload
MIT License
203 stars 10 forks source link

Image cache #46

Open niallobrien opened 7 years ago

niallobrien commented 7 years ago

Hi, I'm new to this but from the docs it's not overly clear how to handle image caching, specifically cache-busting - if I replace an image with a different image (same filename) and request the same dimensions, how can I bust the cache in this scenario to ensure the new image is delivered?

Thanks in advance.

choonkeat commented 7 years ago

The filenames of an upload is largely inconsequential. Every upload is given a unique ID, and is rightly treated as a new file. (Even if it is "an update profile photo" in your application, image servers should treat it as a new image)

So in your application, the flow will be like this

  1. User uploads photo.png
  2. Attache API give a unique path AAAAAAAAA/photo.png
  3. User saves profile, your app stores AAAAAAAAA/photo.png in db
  4. User load profile, your app shows <img src=AAAAAAAAA/photo.png>

if I replace an image with a different image (same filename)

  1. User update profile and uploads a modified photo.png
  2. Attache API give a unique path BBBBB/photo.png
  3. User saves profile, your app stores BBBBB/photo.png in db
    • attache-rails will automatically detect that AAAAAAAAA/photo.png is superceded, and ask attache server to delete that file
  4. User load profile, your app shows <img src=BBBBB/photo.png>

As you can see, (4) and (8) are loading totally different images, so there is no cache to bust

niallobrien commented 7 years ago

Hi @choonkeat, thanks for clarifying. So does this mean that for every image request, there's a DB lookup involved? If so, how does this affect performance? Thanks.

choonkeat commented 7 years ago

To use the example scenario above

  1. User load profile, your app shows <img src=AAAAAAAAA/photo.png>
  1. User saves profile, your app stores BBBBB/photo.png in db
  1. User load profile, your app shows <img src=BBBBB/photo.png>

in all scenarios, the first hit to attache for the image will generate a properly resized image. attache serves the image with aggressive caching headers, so browsers won't even hit the internet for subsequent <img src ...> of seen images. even if the browser does reach for the image, it will hit the local disk cache (no cpu spent doing the same dynamically resize).

in the worst case scenario where the local disk cache doesn't have that image anymore (cache automatically remove least recently used items when disk usage becomes too high), it will download from the cloud storage (your s3), perform a resize, cache locally and serve with aggressive caching headers.

niallobrien commented 7 years ago

In your example above, it assumes the client already knows the unique URL for the image. I assume this is done via a client side lib, but let's assume I'm building a native mobile app, I'm not going to know the unique URL so in this scenario wouldn't it have to lookup the image path in the db and return that image? Sorry, but this is all new to me.

choonkeat commented 7 years ago

the client already knows the unique URL for the image

this will always be the case.

your desktop/web/mobile app will always be managing content e.g. list of users (name, bio...), houses for rent (address, price,...), or even a list of photos (date, time, location,...)

these content has to be stored somewhere. if you are a web app talking to a remote server, its content will be stored in a database on the server. if you are a client side mobile app, that does not want to talk to a remote server, its content will be stored in a database on the mobile device itself.

note: attache is NOT your database. if you've uploaded 1 or 1000 images, attache doesn't give you a way to ask "give me the last 10 images". you give attache images, it stores it. you need an image (in a particular resize), it gives it to you