Struct fastly::cache::core::Transaction
source · pub struct Transaction { /* private fields */ }
Expand description
A cache transaction initiated by Transaction::lookup()
.
Transactions coordinate between concurrent actions on the same cache key, incorporating concepts of request collapsing and revalidation, though at a lower level that does not automatically interpret HTTP semantics.
§Request collapsing
If there are multiple concurrent calls to Transaction::lookup()
for the same item and that
item is not present, just one of the callers will be instructed to insert the item into the
cache as part of the transaction. The other callers will block until the metadata for the item
has been inserted, and can then begin streaming its contents out of the cache at the same time
that the inserting caller streams them into the cache.
§Revalidation
Similarly, if an item is usable but stale, and multiple callers attempt a
Transaction::lookup()
concurrently, they will all be given access to the stale item, but
only one will be designated to perform an asynchronous update (or insertion) to freshen the item
in the cache.
§Example
Users of the transactional API should at minimum anticipate lookups that are obligated to insert
an item into the cache, and lookups which are not. If the stale-while-revalidate
parameter is
set for cached items, the user should also distinguish between the insertion and revalidation
cases.
const TTL: Duration = Duration::from_secs(3600);
// perform the lookup
let lookup_tx = Transaction::lookup(CacheKey::from_static(b"my_key"))
.execute()
.unwrap();
if let Some(found) = lookup_tx.found() {
// a cached item was found; we use it now even though it might be stale,
// and we'll revalidate it below
use_found_item(&found);
}
// now we need to handle the "must insert" and "must update" cases
if lookup_tx.must_insert_or_update() {
if let Some(stale_found) = lookup_tx.found() {
// a cached item was found and used above, and now we need to perform
// revalidation
let revalidation_contents = build_contents();
if should_replace(&stale_found, &revalidation_contents) {
// use `insert` to replace the previous object
let mut writer = lookup_tx
.insert(TTL)
.surrogate_keys(["my_key"])
.known_length(revalidation_contents.len() as u64)
.execute()
.unwrap();
writer.write_all(revalidation_contents).unwrap();
writer.finish().unwrap();
} else {
// otherwise update the stale object's metadata
lookup_tx
.update(TTL)
.surrogate_keys(["my_key"])
.execute()
.unwrap();
}
} else {
// a cached item was not found, and we've been chosen to insert it
let contents = build_contents();
let (mut writer, found) = lookup_tx
.insert(TTL)
.surrogate_keys(["my_key"])
.known_length(contents.len() as u64)
// stream back the object so we can use it after inserting
.execute_and_stream_back()
.unwrap();
writer.write_all(contents).unwrap();
writer.finish().unwrap();
// now we can use the item we just inserted
use_found_item(&found);
}
}
Implementations§
source§impl Transaction
impl Transaction
sourcepub fn lookup(key: CacheKey) -> TransactionLookupBuilder
pub fn lookup(key: CacheKey) -> TransactionLookupBuilder
Returns a TransactionLookupBuilder
that will perform a transactional cache lookup.
See Transaction
for details and an example.
sourcepub fn found(&self) -> Option<Found>
pub fn found(&self) -> Option<Found>
Returns a Found
object for this cache item, if one is available.
Even if an object is found, the cache item might be stale and require updating. Use
Transaction::must_insert_or_update()
to determine whether this transaction client is
expected to update the cached item.
sourcepub fn must_insert(&self) -> bool
pub fn must_insert(&self) -> bool
Returns true
if a usable cached item was not found, and this transaction client is
expected to insert one.
Use Transaction::insert()
to insert the cache item, or
Transaction::cancel_insert_or_update()
to exit the transaction without providing an
item.
sourcepub fn must_insert_or_update(&self) -> bool
pub fn must_insert_or_update(&self) -> bool
Returns true
if a fresh cache item was not found, and this transaction client is expected
to insert a new item or update a stale item.
Use:
Transaction::update()
to freshen a found item by updating its metadata;Transaction::insert()
to insert a new item (including object data);Transaction::cancel_insert_or_update()
to exit the transaction without providing an item.
sourcepub fn cancel_insert_or_update(&self) -> Result<(), CacheError>
pub fn cancel_insert_or_update(&self) -> Result<(), CacheError>
Cancels the obligation for this transaction client to insert or update a cache item.
If there are concurrent transactional lookups that were blocked waiting on this client
to provide the item, one of them will be chosen to be unblocked and given the
Transaction::must_insert_or_update()
obligation.
This method should only be called when Transaction::must_insert_or_update()
is true;
otherwise, a CacheError::InvalidOperation
will be returned.
sourcepub fn insert(self, ttl: Duration) -> TransactionInsertBuilder
pub fn insert(self, ttl: Duration) -> TransactionInsertBuilder
Returns a TransactionInsertBuilder
that will perform a transactional cache insertion.
This method should only be called when Transaction::must_insert_or_update()
is true;
otherwise, a CacheError::InvalidOperation
will be returned when attempting to execute
the insertion.
sourcepub fn update(self, ttl: Duration) -> TransactionUpdateBuilder
pub fn update(self, ttl: Duration) -> TransactionUpdateBuilder
Returns a TransactionUpdateBuilder
that will perform a transactional cache update.
Updating an item freshens it by updating its metadata, e.g. its age, without changing the object itself.
This method should only be called when Transaction::must_insert_or_update()
is true
and the item is found (i.e. Transaction::found()
is non-empty). Otherwise, a
CacheError::InvalidOperation
will be returned when attempting to execute the update.
The method consumes the transaction. Call Transaction::found()
before this method if
subsequent access to the stale cached item is needed.
Important note: the TransactionUpdateBuilder
will replace all of the configuration
in the underlying cache item; if any configuration is not set on the builder, it will revert
to the default value. So, for example, if a cached item previously had some surrogate keys
set, and you want to retain them, you must call
TransactionUpdateBuilder::surrogate_keys()
with the desired keys. Most configuration is
available in the Found
object.
Note: the above behavior is likely to be replaced with defaulting the builder to the existing configuration, making it easier to retain the configuration by default. This change will be noted in a future changelog.