The code should do the following:
How can I keep the cache sync with database to avoid errors?
code
$maxLock = 60;
$lock = Cache::lock("cacheLock", $maxLock);
$lock->block($maxLock);
$cachedIds = Cache::get("cachedIds");
if (empty($cachedIds)) {
$cachedIds = $product
->orders()
->whereNot('status', 'expired')
->implode('id', ',');
$cachedIds = empty($cachedIds)
? []
: explode(',', $cachedIds);
}
$order = new ProductOrder();
$order->fill($request->all());
$order->save();
Cache::put("cachedIds", array_merge($cachedIds, [$order->id]), 60 * 60);
return to_route('checkout', $product->url);
The fact you do $product->orders()
implies you're keeping one cached entry per product. Is that right? In any case, you can use Cache::remember(key, ttl, callback)
to achieve what you want.
Let's say for this example $product
's id is 1
// If the cache has the key 'cached-order-ids-for-product-1' ?
// $id_array = Cache::get('cached-order-ids-for-product-1')
// If the cache doesn't have the key 'cached-order-ids-for-product-1'
// Run callback
// $id_array = result of callback
// Create cache key 'cached-order-ids-for-product-1' and put result of callback as its value. Make it expire in the time specified in ttl
$id_array = Cache::remember(
key: 'cached-order-ids-for-product-'.$product->id,
ttl: 60 * 60,
callback: function () use ($product) {
return $product->orders()
->whereNot('status', 'expired')
->implode('id', ',');
}
);
And then every time you do something that would alter this value, simply use Cache::forget()
.
$new_order = $product->orders()->create($request->validated());
Cache::forget('cached-order-ids-for-product-'.$product->id);