90€ an hour. That's what I ask for freelance work. Contact me.
Laravel

Flexible Caching in Laravel Made Super Easy

Benjamin Crozat
Published on Sep 29, 2024 0 comments Edit on GitHub
Flexible Caching in Laravel Made Super Easy

Introduction

Laravel 11 introduces a powerful new caching feature that promises to revolutionize how we handle expensive data operations. The new Cache::flexible() method implements a pattern that allows serving cached data while updating it in the background, offering a smart solution to the age-old problem of balancing data freshness with application performance. In this post, we’ll explore this feature, starting with the basics and gradually diving into more advanced use cases.

Understanding the Two-Tier TTL System

The key innovation in Cache::flexible() is its two-tier Time To Live (TTL) system. This system defines two important time periods:

  1. The “fresh” period: How long the data is considered up-to-date.
  2. The “grace” period: How long slightly outdated data can be served while a refresh happens in the background.

Here’s a simple example to illustrate:

use Illuminate\Support\Facades\Cache;
use Carbon\Carbon;

$value = Cache::flexible(
    key: 'my_data',
    ttl: [
        Carbon::minutes(5),  // Fresh period.
        Carbon::minutes(15)  // Total lifespan (fresh + grace period)
    ],
    callback: function () {
        // Expensive operation here.
    }
);

In this case:

  • For the first 5 minutes, the data is considered fresh and will be served directly from the cache.
  • From 5 to 15 minutes, the data enters the grace period. It will still be served from the cache, but a background process will be triggered to update it.
  • After 15 minutes, the data is considered expired. The next request will wait for the data to be recalculated before responding.

This two-tier system allows your application to:

  1. Serve fresh data most of the time
  2. Maintain responsiveness even when data needs updating
  3. Ensure data doesn’t become too outdated

By specifying both durations, you have fine-grained control over the balance between data freshness and application performance.

Real-World Application: E-commerce Recommendations

Let’s look at a more practical example. Imagine we’re running an e-commerce site and want to display personalized product recommendations:

use Illuminate\Support\Facades\Cache;
use Carbon\Carbon;

$recommendations = Cache::flexible(
    key: 'user_recommendations:' . $userId,
    ttl: [
        Carbon::minutes(5),
        Carbon::minutes(15)
    ],
    callback: function () use ($userId) {
        return $this->recommendations->get($userId);
    },
    lock: ['seconds' => 10]
);

This setup allows us to serve personalized recommendations quickly, even if they’re slightly outdated, while ensuring that the computationally expensive recommendation algorithm doesn’t run too frequently.

Advanced Usage: Dashboard Analytics

For more complex scenarios, like caching aggregate analytics data for a dashboard, we can leverage Cache::flexible() to balance data freshness with system performance:

use Illuminate\Support\Facades\Cache;
use Carbon\Carbon;

$stats = Cache::flexible(
    key: 'dashboard_stats',
    ttl: [
        Carbon::minute(),
        Carbon::minutes(10)
    ],
    callback: function () {
        return [
            'total_sales' => Order::sum('total'),
            'new_users' => User::where('created_at', '>=', now()->subDay())->count(),
            'popular_products' => Product::withCount('orders')
                ->orderByDesc('orders_count')
                ->limit(5)
                ->get()
        ];
    }
);

This approach is particularly useful for data that’s expensive to calculate but doesn’t need to be real-time accurate.

Handling High-Traffic Scenarios

In high-traffic situations, we can use the lock configuration to prevent multiple processes from attempting to refresh the cache simultaneously:

use Illuminate\Support\Facades\Cache;
use Carbon\Carbon;

Cache::flexible(
    key: 'high_traffic_key',
    ttl: [
        Carbon::seconds(30),
        Carbon::minute()
    ],
    callback: function () {
        // Expensive operation here
    },
    lock: [
        'seconds' => 5, 
        'owner' => 'custom_owner'
    ]
);

This lock ensures that only one process attempts to refresh the cache at a time, preventing redundant work and potential race conditions.

When Not to Use Flexible Caching

While Cache::flexible() is a powerful tool, it’s not suitable for all types of data. Security-critical information, such as user authentication tokens, should not use this caching method, as serving slightly outdated data could lead to security vulnerabilities.

Conclusion

Laravel 11’s Cache::flexible() method provides a nuanced approach to caching that can significantly improve application performance in many real-world scenarios. By allowing controlled use of slightly outdated data, it strikes a balance between data freshness and system responsiveness.

When used appropriately, this feature can lead to more responsive applications and a better user experience overall.

Be the first to comment!

Get help or share something of value with other readers!

Great deals for enterprise developers
  • Summarize and talk to YouTube videos. Bypass ads, sponsors, chit-chat, and get to the point.
    Try Nobinge →
  • Monitor the health of your apps: downtimes, certificates, broken links, and more.
    20% off the first 3 months using the promo code CROZAT.
    Try Oh Dear for free
  • Keep the customers coming; monitor your Google rankings.
    30% off your first month using the promo code WELCOME30
    Try Wincher for free →
The latest community links
- / -