#object #cache #generic #ttl #back #call #defined

generic_cache

Easy to use object caching based on defined TTL

5 releases (breaking)

new 0.5.0 Mar 5, 2025
0.4.0 Mar 3, 2025
0.3.0 Feb 28, 2025
0.2.0 Feb 24, 2025
0.1.0 Feb 22, 2025

#93 in Caching

Download history 235/week @ 2025-02-21 343/week @ 2025-02-28

578 downloads per month

MIT license

14KB
165 lines

generic_cache

A generic cached object which provide user two possible usage options.

  1. Use Object::get() until it return TimeoutError then manually call Object::refresh() function.
  2. Use Object::get_or_refresh() which will automatically refresh the value when it is expired.

Rationale

For performance critical application, most of the time, major cost came from IO. To reduce cost, the easiest way is to cache the value. In some case, it is possible to delegate this work to network layer, e.g. Proxy. In some other case, it is not possible due to security reason. An example of such case is the bearer token which is used to communicate between API server. It is normally obtained via HTTP POST which proxy won't cache. In such case, some vendor provide a library which handle token caching but it is not always the case. This is where this library fit in.

Breaking change

Version 0.3.0

  • Change ttl argument type from u128 to std::time::Duration type.

lib.rs:

A generic cached object which provide user two possible usage options.

  1. Use [Object::get()] until it return [TimeoutError] then manually call [Object::refresh()] function.
  2. Use [Object::get_or_refresh()] which will automatically refresh the value when it is expired.

The different between the two is that the [Object::get()] is more flexible because it only borrow the cache value while the [Object::get_or_refresh()] will required a borrow mut of [Object] itself because it might need to change the cached value. However, the auto refresh is convenient because user doesn't need to handle [TimeoutError] when cache is expired. Both usage options still need to handle refresh_fn error if any.

Example

  • Verify two cached call to get value back to back to check if it is actually the same value.
use generic_cache::Object;

let cached = Object::new(std::time::Duration::from_secs(1), 100, async || {Ok::<u16, ()>(200)}); // Explicitly define type for Error. Otherwise, compile will fail.
let first = cached.get().unwrap();
let second = cached.get().unwrap();
assert_eq!(*first, 100, "Expect {} to equals {}", *first, 0);
assert_eq!(first, second, "Expect {} to equals {}", first, second);
  • Check for expired then refresh the cache
use core::time;
use std::thread::sleep;
use generic_cache::Object;

let mut cached = Object::new(std::time::Duration::from_millis(100), 100, async || {Ok::<u16, ()>(200)}); // Explicitly define type for Error. Otherwise, compile will fail.
let first = *cached.get().unwrap();
sleep(time::Duration::from_millis(200));
if let Ok(_) = cached.get() {
    panic!("Cache should be expired but it is not.")
} else {
    cached.refresh().await.unwrap();
}
let second = *cached.get().unwrap();
assert_ne!(first, second, "Expect {} to equals {}", first, second);
  • Auto refresh expired cache value
use core::time;
use std::thread::sleep;
use generic_cache::Object;

let mut cached = Object::new(std::time::Duration::from_secs(0), 100, async || {Ok::<u16, ()>(200)}); // Explicitly define type for Error. Otherwise, compile will fail.
let first = *cached.get_or_refresh().await.unwrap();
sleep(time::Duration::from_millis(1));
let second = *cached.get_or_refresh().await.unwrap();
assert_eq!(first, second, "Expect {} to equals {}", first, second);
  • No default value when create a cache and auto refresh expired cache value
use core::time;
use std::thread::sleep;
use generic_cache::Object;

let mut cached = Object::new_and_refresh(std::time::Duration::from_secs(1), async || {Ok::<u16, ()>(200)}).await.unwrap(); // Explicitly define type for Error. Otherwise, compile will fail.
let first = *cached.get_or_refresh().await.unwrap();
let second = *cached.get_or_refresh().await.unwrap();
assert_eq!(first, second, "Expect {} to equals {}", first, second);

No runtime deps