henzeb/warmable

框架无关的缓存预热器

v1.1.0 2024-02-22 10:13 UTC

This package is auto-updated.

Last update: 2024-09-22 11:26:16 UTC


README

Latest Version on Packagist Total Downloads

本软件包受到了@timacdonald的一次演讲的启发,他在演讲中展示了一种通过简单的可调用类预热缓存条目的技术。

当你缓存了复杂操作的结果,偶尔会有用户需要等待操作被重新缓存。如果请求速率足够高,可能有多个人同时需要这样做。

本软件包提供了实现这一点的框架。它实现了PSR16缓存接口,因此几乎支持你能够想到的所有缓存机制,如果不支持,你可以实现一个包装器,它仍然支持你能够想到的所有缓存机制。

Laravel开发人员也可以使用此软件包,但为了充分利用Laravel的功能,最好是安装并使用Warmable for Laravel

安装

只需使用以下命令进行安装。

composer require henzeb/warmable

术语

预热/正在预热

预热正在预热这一术语指的是在计划任务或队列任务中缓存。

预加热

当缓存在与执行的同时填充时使用此术语,这是缓存不存在时的默认操作。这也可以分发给像队列系统这样的后台操作。

用法

创建Warmable

创建Warmable非常简单。

use Henzeb\Warmable\Warmable;
use Psr\SimpleCache\CacheInterface;
use DateTimeInterface;
use DateInterval;

class HeavyOperation extends Warmable
{
    protected function key() : string
    {
        // ... return your key
    }
    
    protected function ttl() : DateTimeInterface|DateInterval|int|null
    {
        // ... return your desired ttl
    }
    
    protected function gracePeriod() : DateTimeInterface|DateInterval|int|null
    {
        // ... return your desired grace period
    }
    
    protected function cache(): CacheInterface 
    {
         // ... your cache implementation
    }
    
    protected function warmable(): mixed 
    {
         // ... your heavy operation
    }
}

注意:可以省略keyttl。省略key时,将基于你的对象的FQCN生成一个键。省略ttl时,Warmable结果将永久存储在缓存中。

链式方法。

Warmable允许链式调用方法。你可以从任何你希望的方法开始。

HeavyOperation::withKey('yourKey')->get();

HeavyOperation::withTtl(300)->withKey('yourKey')->get();

HeavyOperation::withKey('yourKey')->withTtl(300)->get();

make

使用make可以轻松获取你的Warmable实例。你可以添加传递给构造函数的参数。

// equivalent to new HeavyOperation();
HeavyOperation::make(); 

// equivalent to new HeavyOperation(new YourService());
HeavyOperation::make(new YourService()); 

get

使用此方法可以轻松访问缓存数据。

HeavyOperation::get();
HeavyOperation::make()->get();

默认情况下,如果尚未存在,Warmable会预先加热数据。如果你不希望在响应之前发生这种情况,可以设置默认值。在这种情况下,它将在将响应发送到浏览器之后才执行该操作。

HeavyOperation::get([]);

HeavyOperation::get(true);

HeavyOperation::get(fn()=>false);

注意:这不适用于null。请使用withoutPreheating代替。

with

Warmable方法支持基本的依赖注入。使用此方法,你可以使缓存对每个用户或项目是唯一的。你不需要做任何事情,只需将其传递给构造函数即可。

use Henzeb\Warmable\Warmable;

class HeavyOperation extends Warmable
{
    // ...
    
    public function warmable(int $id): mixed {
        // ...
        return 'this is '.$id;
    } 
}

HeavyOperation::with(12)->get(); // returns 'this is 12'
HeavyOperation::with(14)->get(); // returns 'this is 14'
HeavyOperation::with(12)->get(); // returns 'this is 12' from cache
HeavyOperation::with(14)->get(); // returns 'this is 14' from cache

key

默认情况下,Warmable会为你生成一个唯一的键。你不需要做任何事情。即使你想为不同的项目重用WarmableWarmable也会为你提供支持。但如果你想自定义键,有两种方法可以做到这一点。

第一种是在你的Warmable类上设置key方法。

use Henzeb\Warmable\Warmable;

class HeavyOperation extends Warmable {
    protected function key() : string{
        return 'your-key';
    }    
}

HeavyOperation::get(); // retrieves from 'your-key'
HeavyOperation::with(12)->get(); // retrieves from 'your-key.<sha1 hash>'

第二种方法是内联的。

HeavyOperation::withKey('other-key')->get(); // retrieves from 'other-key'
HeavyOperation::withKey('other-key')
->with(12)
->get(); // retrieves from 'other-key.<sha1 hash>'

缓存

缓存显然是必需的元素。通过强制性的cache方法设置。还有一个可以内联使用的withCache方法。

use Psr\SimpleCache\CacheInterface;
HeavyOperation::withCache(<CacheInterface::class>);
HeavyOperation::make()->withCache(<CacheInterface::class>);

注意:Warmable接受任何实现了PSR-16 CacheInterface的缓存实现。如果你使用的缓存系统没有实现它,你可以轻松创建一个实现了它的包装器。

生存时间 (TTL)

允许您使用与类内部定义的不同 TTL。

注意,Ttl 默认为 null,因此默认为 永远

use Henzeb\Warmable\Warmable;

class HeavyOperation extends Warmable
{
    protected function ttl(): DateTimeInterface|DateInterval|int|null {
         return DateInterval::createFromDateString('300 seconds');
    }
}

或者您可以直接设置

use Henzeb\Warmable\Warmable;

// expires on given date
HeavyOperation::withTtl(new DateTime('2024-02-31 23:00'));

// expires in 300 seconds
HeavyOperation::withTtl(
DateInterval::createFromDateString('300 seconds')
);

// expires in 300 seconds
HeavyOperation::withTtl(300);

宽限期

与 TTL 结合使用,宽限期允许您在更新缓存的同时向用户提供旧数据。此更新发生在返回浏览器响应之后。

以下示例将创建一个存活时间为 600 秒的缓存项。在 300 秒后,下一次调用将返回缓存中的值,并注册一个更新缓存项的关闭函数,该缓存项将存活 600 秒,依此类推。

use Henzeb\Warmable\Warmable;

class HeavyOperation extends Warmable
{
    protected function ttl(): DateTimeInterface|DateInterval|int|null {
         return 300
    }
    
    protected function gracePeriod(): DateTimeInterface|DateInterval|int|null {
         return 300
    }
}

getKey

有时您可能需要查看您的 Warmable 使用的键。

// returns warmable.HeavyOperation
HeavyOperation::getKey();

// returns test
HeavyOperation::withKey('test')->getKey();
 
// returns test.<sha1 hash>
HeavyOperation::withKey('test')->with(id)->getKey(); 

missing

// returns true
HeavyOperation::missing();
// returns false
HeavyOperation::get(); // will preheat the cache
HeavyOperation::make()->missing();
HeavyOperation::missing();

isPreheated

此方法告诉您缓存是否已预热。

$operation = HeavyOperation::make();
$operation->isPreheated(); // returns false
$operation->get(); // will preheat the cache
$operation->isPreheated(); // returns true

withoutPreheating

此方法允许您显式禁用预热。

HeavyOperation::withoutPreheating()->get(); // returns null when not warmed up

// and when called again:
HeavyOperation::withoutPreheating()->get(); // returns null when not warmed up

withPreheating

withoutPreheating 完全相同,但它切换了预热。

// would preheat the warmable data.
HeavyOperation::withPreheating()->get(); 

// would preheat the data after shutdown, and return default instead.
HeavyOperation::withPreheating()->get([]); 

shouldPreheat

此方法告诉您预热标志是否开启。

HeavyOperation::shouldPreheat(); // returns true (default)
HeavyOperation::withPreheating()->shouldPreheat(); // returns true
HeavyOperation::withoutPreheating()->shouldPreheat(); // returns false

cooldown

如果由于某些原因需要删除缓存,可以调用 cooldown

HeavyOperation::cooldown();
HeavyOperation::make()->cooldown();

自定义预热策略

如果您的应用程序可以访问队列,则很容易更改预热策略。默认情况下,它会在执行时进行预热。

use Henzeb\Warmable\Warmable;

class HeavyOperation extends Warmable
{
    // ... your Warmable definition
    
    protected function getPreheated(bool $hasDefault): mixed
    {
        // ...
    }
}

注意:返回 null 会导致 get 方法使用默认值。

重写公共接口

在底层,Warmable 使用 __call__callStatic 来允许链式静态和动态调用。如果您想重写公共接口上的方法,您应该找到它的 call<method> 对应方法。

例如:如果您想重写 with 方法,您应该扩展 callWith 方法。

测试

composer test

贡献

请参阅 CONTRIBUTING 以获取详细信息。

安全

如果您发现任何安全相关的问题,请通过电子邮件 henzeberkheij@gmail.com 而不是使用问题跟踪器。

鸣谢

许可证

GNU AGPLv. 请参阅 许可证文件 以获取更多信息。