Skip to content

tbessenreither/multi-level-cache

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

30 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MultiLevelCache Symfony Bundle

A high-performance, multi-level caching system for Symfony applications. This bundle provides a flexible, extensible, and developer-friendly way to combine multiple cache backends (memory, Redis, file, etc.) for optimal speed and reliability.

It has two parts to it.

  1. The Multi Level Cache Itself.
  2. The Cached Service Generator

The Main way of using this package is via the Cached Service Generator (CSG), so this will be the focus of this documentations. Details can be found [todo: write an actuall in depth documentation of the MLC] here

Installation

Install via Composer from GitHub:

  1. Add the repository to your composer.json:
    {
      "repositories": [
        {
          "type": "vcs",
          "url": "https://github.com/tbessenreither/multi-level-cache"
        }
      ]
    }
  2. Require the package:
    composer require tbessenreither/multi-level-cache
  3. Enable the Bundle in config/bundles.php:
    Tbessenreither\MultiLevelCache\MultiLevelCacheBundle::class => ['all' => true],
  4. Configure Environment Variables as needed:
    • REDIS_DSN (if using Redis, so basically always)
    • MLC_DISABLE_READ (optional, disables cache reads)
    • MLC_COLLECT_ENHANCED_DATA (optional, enables enhanced data collection but has performance impact)

The Multi-Level-Cache (MLC)

Basic concept

Its a fast multi level cache consisting, in it's standard configuration, of:

  • a fast In Memory Ring Cache
  • and a second Level Redis Cache

Most notable features

  • Faster and much more Memory Efficient than the Symfony Cache (We love it, but we needed something faster)
  • Cache statistics and profiling (Symfony Profiler integration)
  • Beta decay and TTL randomization to prevent stampedes
  • Exception handling and diagnostics

The Cached Service Generator

This is the main thing you hopefully will interact with as the goal of this package is to make manual cache implementations a thing of the past.

Overview

This is the main way of using the MLC. The basic idea is to implement your services without any caching logic and then wrapp them within an API Compatible Wrapper (Front Loaded Caching).

To create a cached version of a service you can use the ddev mlc-make App.Service.TestService command.

Cachable Methods are marked as such with the #[MlcCachableMethod(ttlSeconds: 300)] attribute. Everything else is hands off.

Basic relation between the Source and the Cached Service

Basic Principle of the CacheGenerator

Usage

Making your Service Ready for Caching

Given this example TestService

<?php
declare(strict_types=1);

namespace Tbessenreither\Example\Service;

use Tbessenreither\Example\Entity\HotelEntity;
use Tbessenreither\MultiLevelCache\CachedServiceGenerator\Attribute\MlcCachableMethod;

readonly class TestService 
{
    public function getHotel(string $id): HotelEntity
    {
        return $this->getBrandByIri(sprintf('%s/%s', self::getApiUrl(), $id));
    }

    #[MlcCachableMethod(ttlSeconds: 600)]
    public function getHotelByIri(string $iri): HotelEntity
    {
        $brand = $this->getObjectContent(
            pageId: $iri,
            query: [],
            className: HotelEntity::class
        );

        return $brand;
    }

    // [...]
}

Generating the cached service

We've added the Attribute to the Endpoint we want to cache. And now we need to run ddev mlc-make Tbessenreither.Example.Service to generate our Cache wrapper. Now the following will happen.

  1. It will create a TestServiceInterface for the TestService.
  2. The Generator will create a wrapper under the name TestServiceCached that implements the TestServiceInterface to ensure compatibility
  3. It will add the TestServiceInterface to the original Class

The Cache Wrapper is stored in the same directory as your Original TestService postfixed with Cached giving you TestServiceCached.

The TestServiceInterface will be put into the appropriate Interface directory.

The Output of the make command will look somewhat like this:

Example Output of mlc-make

Using the cached service

You basically have two options here.

  1. You can either swap out the TestService for TestServiceCached directly as a drop in replacement
  2. Or you can inject the TestServiceInterface and configure the Version you want to use via the services.yaml

Do whatever fits your needs best. The MLC has no opinions on how to do this.

Updating the cached services

This is nice and all. But what if i change something in my TestService? Do i need to update everything again?

No, good god no.

You just run ddev mlc-update. This command will auto detect all Cache Wrappers and update them + the interfaces with the latest methods and MlcCachableMethod annotations.

The command output will show you something like this:

Output of the ddev mlc-update command

If any service can't be updated (There are some reasons why this might happen) it will show this in the status collumn and print a detailed reason in the Message collumn.


License

MIT

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published