Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to disable memory cache TTL extending #1196

Merged

Conversation

dstranz
Copy link
Contributor

@dstranz dstranz commented May 29, 2019

Use case:

Let's assume that we are having an image that is valid for a limited time. For example, USD/EUR rating chart that should be reloaded every 3 minutes. So we are using .memoryCacheExpiration(.seconds(3 * 60)) option.

It's not worth to cache it on disk, because we will replace it every 3 minutes. So we are using .cacheMemoryOnly option.

What will be the expected result?

After reloading the chart view we will get from Kingfisher cached image if not older than 3 minutes or a fresh one.

What is actual behavior?

After reloading the chart view we will get from Kingfisher cached image if the time between last image load isn't longer than 3 minutes or a fresh one.

Proposed change

In many cases actual behavior is correct. Why not extending TTL time for frequently used user avatar or media that will be the same every time we will load it?

But in other cases when the image should be not older than given TTL time we should add an option to disable extending functionality.

That's the reason why I've added a new option to Kingfisher called .memoryCacheExpirationNotExtendable.

@dstranz
Copy link
Contributor Author

dstranz commented May 29, 2019

I haven't got any problems with tests locally. They also pass on most of travis builds but not on all, so they are not reliable.

@onevcat Do you know what will a be better way to test cache TTL extending - probably without delay?

@onevcat
Copy link
Owner

onevcat commented May 30, 2019

@dstranz

Thanks for the proposal and implementation!

The CI sometimes does not work well due to some limitation on infrastructure. I will check it later, for both the use case and the tests.

Copy link
Contributor

@RomanPodymov RomanPodymov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @dstranz
Try gem "cocoapods", "~> 1.7.1". I used it in #1199 and all checks have passed.

@dstranz
Copy link
Contributor Author

dstranz commented Jun 3, 2019

Thank you for the suggestion @RomanPodymov.

It looks that it's not the only cause of failure.

IMO the idea to test cache that way, with delays doesn't work well on CI because (probably) there are some slow downs and cache time elapsed before the last delayed block.

https://travis-ci.org/onevcat/Kingfisher/jobs/540614120
✅ testCacheImageExtendingExpirationTask passed
🔴 testCacheImageExpirationTask failed

https://travis-ci.org/onevcat/Kingfisher/jobs/540614130
🔴 testCacheImageExtendingExpirationTask failed
✅ testCacheImageExpirationTask passed

I need to figure out better way to test cache with/without memoryCacheExpirationNotExtendable option.

dstranz added 2 commits June 3, 2019 16:46
….com:dstranz/Kingfisher into feature/option-to-ignore-extendingExpiration
@@ -203,6 +203,10 @@ public enum KingfisherOptionsInfoItem {
/// value to overwrite the config setting for this caching item.
case memoryCacheExpiration(StorageExpiration)

/// By default, every read operation for an item is extending it's expiration time. Use this setting to
/// disable this behavior and expire item regardless it's next requests.
case memoryCacheExpirationNotExtendable
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's good to have this option. However, maybe we could make it more generic. Currently, we are extending the expiration duration according to the original .memoryCacheExpiration setting. Let's make it something like .memoryCacheAccessExtendingExpiration(StorageExpiration) so we can control it better. For example, in your case, you send a . memoryCacheAccessExtendingExpiration(.seconds(0)) to prevent the extending, while others can choose . memoryCacheAccessExtendingExpiration(.days(3)) to extend it by 3 days or .memoryCacheAccessExtendingExpiration(.expired) to make it expired immediately.

And maybe we could do the same thing to the disk cache, so we can solve #1152 as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@onevcat Please take a look at the implementation of .memoryCacheAccessExtendingExpiration(StorageExpiration).

In case of not extending I use .memoryCacheAccessExtendingExpiration(.never).

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dstranz Great!

In case of not extending I use .memoryCacheAccessExtendingExpiration(.never).

I can understand your concerns here. However, I am not feeling good to have different meanings on .never: in the .memoryCacheExpiration it means "not expiring at all" but in .memoryCacheAccessExtendingExpiration now it is "not extending". This would definitely brings confusion and issues in future, even you have written great documentation on it.

Maybe we would need another enum besides of StorageExpiration (something like ExpirationExtending), or maybe we need to reconsider the name of .memoryCacheAccessExtendingExpiration if we want to keep using StorageExpiration as the associated value type. I personally prefer the former. Do you have any better idea?

Copy link
Contributor Author

@dstranz dstranz Jun 5, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, we could use .memoryCacheAccessExtendingExpiration(.seconds(0)) as "not extend" case. I understand your reason to not use .never but in such case without special treatment it will change TTL to 0 seconds and expire cache instead of not extending. Of course, we could add there guard expiration.timeInterval != 0 to change default behavior.

I had something similar to ExpirationExtending yesterday, but later removed that. What do you think about such cases:

enum ExpirationExtending {
case .none
case .cacheTime
case .expirationTime(_ expiration: StorageExpiration)
}

Default value in Options will be .cacheTime as before change.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. I think your ExpirationExtending definition is so nice!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@onevcat I've just pushed the code with ExpirationExtending.

@onevcat
Copy link
Owner

onevcat commented Jun 3, 2019

CI machines are quite slow and it is not safe to judge a duration like 0.05s. I suggest make it 0.1, 0.3, 0.5s, which can improve the CI stability. Or instead of checking whether it is retrieved from memory cache or not, you can check the expiration duration after the access to confirm whether the time is extended, which might be also stable than a timer.

@dstranz
Copy link
Contributor Author

dstranz commented Jun 4, 2019

Or instead of checking whether it is retrieved from memory cache or not, you can check the expiration duration after the access to confirm whether the time is extended, which might be also stable than a timer.

I've just rewritten both failing tests and then see your comment. Looks like we had similar idea. I'm only not sure if it's the best way to obtain expiration date:

let cacheKey = result.value!.source.cacheKey as NSString
let expirationTime1 = ImageCache.default.memoryStorage.storage.object(forKey: cacheKey)?.estimatedExpiration

It's good to have this option. However, maybe we could make it more generic.

I will look at that when tests will pass for current solution 😉

Sources/Cache/Storage.swift Outdated Show resolved Hide resolved
Sources/Cache/Storage.swift Outdated Show resolved Hide resolved
dstranz and others added 2 commits June 5, 2019 16:02
Co-Authored-By: Wei Wang <onevcat@gmail.com>
Co-Authored-By: Wei Wang <onevcat@gmail.com>
@onevcat
Copy link
Owner

onevcat commented Jun 5, 2019

All green! Thanks a lot for that, @dstranz It is awesome.

@onevcat onevcat merged commit ff4a917 into onevcat:master Jun 5, 2019
@dstranz dstranz deleted the feature/option-to-ignore-extendingExpiration branch June 6, 2019 07:03
@onevcat onevcat mentioned this pull request Nov 6, 2019
2 tasks
skoduricg pushed a commit to rentpath/Kingfisher that referenced this pull request Sep 24, 2021
…-extendingExpiration

Add option to disable memory cache TTL extending
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants