Baseflow / flutter_cache_manager

Generic cache manager for flutter
https://baseflow.com
MIT License
740 stars 429 forks source link

stalePeriod clarification #283

Open nt4f04uNd opened 3 years ago

nt4f04uNd commented 3 years ago

i used to think that maxAgeCacheObject, which was i guess replaced with stalePeriod worked like so: we download file -> mark some expiry date for it -> when it's expired we redownload it

with current docs it seems that's not the case https://github.com/Baseflow/flutter_cache_manager/blob/46f0a0466d62350b48a520a5561fd59e0c546dda/flutter_cache_manager/lib/src/cache_manager.dart#L32-L33

so if i have stalePeriod that equals to 1 day and user opens my app each 12 hours, for instance, and the file is being reused, my cache will never be invalidated? if that's true, how do i change this?

renefloor commented 3 years ago

Yes, that's exactly why there was a rename with a better documentation. You can only control how long you want to have the file on disk. The server controls how long the image is valid using the cache-control max-age header. If you set the stalePeriod on 1 day, but the max-age is 2 hours the file can be served from cache after 4 hours, but the library will check at the server if there is a newer version of the file.

nt4f04uNd commented 3 years ago

does flutter_cache_manager_firebase handle that? if i replace the file in storage it doesn't seem to refetch the new version of file

(i use it for videos)

renefloor commented 3 years ago

I don't know what kind of cache headers are set by firebase. You could check that using postman or something similar.

nt4f04uNd commented 3 years ago

it sets max-age=0 by default. does it mean that file will be automatically replaced on update? (i'm currently migrating to newer version from maxAgeCacheObject)

renefloor commented 3 years ago

Although the name changed the behaviour shouldn't have changed.

When the max-age is 0 it uses a default period of 7 days, because most people will still want to have some cache. When setting the header to 'no-cache' it is really set to 0 seconds. You can see that code here: https://github.com/Baseflow/flutter_cache_manager/blob/develop/flutter_cache_manager/lib/src/web/file_service.dart#L87

nt4f04uNd commented 3 years ago

i just tried setting the stalePeriod to 0, it doesn't work at all and never invalidates the cache

renefloor commented 3 years ago

How did you test this? And it shouldn't invalidate the cache, just remove the files.

nt4f04uNd commented 3 years ago

And it shouldn't invalidate the cache, just remove the files.

yep, that's what i meant actually

How did you test this?

i have an app tied up with the firebase storage. i opened the file once in my app, then changed it in storage, then opened the file again and saw the same cached file, it was not refetched. i tried it multiple times and waited for a few minutes - cached files still weren't deleted, even after app restart

nt4f04uNd commented 3 years ago

hmm, actually wait a bit, i will test it again

renefloor commented 3 years ago

@nt4f04uNd I just did the following test:

void main() {
  runApp(MyApp());
  checkCache();
}

Future<void> checkCache() async {
  var i = 0;
  while (i < 50) {
    CustomCacheManager.instance
        .getFileStream('https://via.placeholder.com/${(i % 5) + 1}',
            withProgress: false)
        .where((e) => e is FileInfo)
        .forEach((element) {
      var fileInfo = element as FileInfo;
      print("${fileInfo.originalUrl} from: ${fileInfo.source}");
    });

    await Future.delayed(Duration(seconds: secondsBetweenPulls));
    i++;
  }
}

class CustomCacheManager {
  static const key = 'customCacheObject';
  static CacheManager instance = CacheManager(Config(key,
      stalePeriod: Duration(seconds: stalePeriodInSeconds), maxNrOfCacheObjects: 1000));
}

Having the following settings it keeps the file in the cache:

var secondsBetweenPulls = 1;
var stalePeriodInSeconds = 30;

I/flutter (30423): https://via.placeholder.com/1 from: FileSource.Cache
I/flutter (30423): https://via.placeholder.com/2 from: FileSource.Cache
I/flutter (30423): https://via.placeholder.com/3 from: FileSource.Cache
I/flutter (30423): https://via.placeholder.com/4 from: FileSource.Cache
I/flutter (30423): https://via.placeholder.com/5 from: FileSource.Cache
I/flutter (30423): https://via.placeholder.com/1 from: FileSource.Cache
I/flutter (30423): https://via.placeholder.com/2 from: FileSource.Cache
I/flutter (30423): https://via.placeholder.com/3 from: FileSource.Cache
I/flutter (30423): https://via.placeholder.com/4 from: FileSource.Cache
I/flutter (30423): https://via.placeholder.com/5 from: FileSource.Cache

The following settings doesn't keep the file in the cache:

var secondsBetweenPulls = 10;
var stalePeriodInSeconds = 10;

I/flutter (30423): https://via.placeholder.com/1 from: FileSource.Cache
I/flutter (30423): https://via.placeholder.com/2 from: FileSource.Cache
I/flutter (30423): https://via.placeholder.com/3 from: FileSource.Online
I/flutter (30423): https://via.placeholder.com/4 from: FileSource.Online
I/flutter (30423): https://via.placeholder.com/5 from: FileSource.Online
I/flutter (30423): https://via.placeholder.com/1 from: FileSource.Online
nt4f04uNd commented 3 years ago

thanks for a great test, i can confirm it works for values you provided, but it doesn't work for me with these

var secondsBetweenPulls = 120;
var stalePeriodInSeconds = 120;

i didn't really try to tweak them to some other values, but in my app when i set stalePeriod to two minutes or so, it simply doesn't work

here's reproducible that uses your test https://github.com/nt4f04unds-archive/issues/tree/flutter_cache_manager_283

use this command to clone it as it has a lot of branches

git clone -b flutter_cache_manager_283 --single-branch git@github.com:nt4f04unds-archive/issues.git
logs ``` I/flutter (12918): https://via.placeholder.com/3 from: FileSource.Online I/flutter (12918): https://via.placeholder.com/3 from: FileSource.Cache I/flutter (12918): https://via.placeholder.com/3 from: FileSource.Cache I/flutter (12918): https://via.placeholder.com/3 from: FileSource.Cache I/flutter (12918): https://via.placeholder.com/3 from: FileSource.Cache I/flutter (12918): https://via.placeholder.com/3 from: FileSource.Cache ```
renefloor commented 3 years ago

You changed the example from downloading 5 different images to only 'https://via.placeholder.com/3'. The library isn't continuously checking the cache, but only 10 seconds after something happened. So every time after you request this file it checks if it is recently used and it will never be stale (because you just requested it). If you change that file to 'https://via.placeholder.com/${(i % 5) + 1}' I expect it to work.

nt4f04uNd commented 3 years ago

ok thanks for detailed explanations could you put those in documentation? this would be really helpful

billyonggoorigaming commented 3 years ago

The current documention says:

When are the cached files updated? A valid url response should contain a Cache-Control header. More info on the header can be found here, but in summary it says for how long the image can be expected to be up to date. It also contains an 'eTag' which can be used to check (after that time) whether the file did change or if it is actually still valid.

Following the provided link about Cache-Control header, we can see this:

no-cache and max-age=0, must-revalidate indicates same meaning. Clients can cache a resource but must revalidate each time before using it. This means HTTP request occurs each time though, it can skip downloading HTTP body if the content is valid

But for flutter_cache_manager it is:

When the max-age is 0 it uses a default period of 7 days, because most people will still want to have some cache. When setting the header to 'no-cache' it is really set to 0 seconds.

@renefloor Wouldn't it be better for max-age=0 to behave like what's written in the Mozilla's documentation, which has the same meaning to no-cache?

If not, adding the default to 7 days to the documentation would be really helpful.

renefloor commented 3 years ago

I agree that it should be better documented. I think max-age=0 is often set because devs just miss setting it. However, we got many complaints about the library not caching when we adhered to the 'max-age'. The Cache-Control: no-cache header is often added more deliberately in my experience.