henzeb/warmable-laravel

Laravel 框架的缓存预热器

v0.1.0 2024-02-19 12:00 UTC

This package is auto-updated.

Last update: 2024-09-22 10:19:05 UTC


README

Latest Version on Packagist Total Downloads

本包受到 2024 年 LaraconEU 大会 @timacdonald 的启发,他在会上展示了一种使用简单的可调用类预热的缓存条目的技术。

当你缓存一个重操作的结果时,有时用户将不得不等待操作再次被缓存。如果请求速率足够高,可能有多个人同时这样做。

本包旨在通过利用调度器和队列尽可能减少这种情况。

它主要针对 Laravel 构建,但由于我使用了 PSR-16 psr/simple-cache CacheInterface,任何人都可以使用它。只需安装纯净的 Warmable 即可,因为这个包是 Laravel 特定的

安装

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

composer require henzeb/warmable-laravel

术语

预热/正在预热

预热或正在预热是指通过 cron 或队列进行缓存。

预加热

预加热是指在执行过程中填充缓存时使用的术语,这是缓存不存在时的默认操作。这也可以派发到像队列系统这样的后台操作。

使用

这里的说明是针对 Laravel 的。有关更多信息,请参阅 Warmable 的文档。

创建一个可预热对象

创建一个 Warmable 非常简单。正如你所看到的,不需要 cache 方法,因为默认情况下,Warmable 使用默认的 Cache 驱动器。

你仍然可以选择覆盖它并使用不同的驱动器。你不必坚持使用 CacheInterface 实现,你也可以使用字符串。你可以在任何可以输入缓存驱动器的地方使用字符串。

注意:实际上,使用字符串在性能上更好,因为当在队列中进行序列化时,它需要遍历所有配置的存储来确定其名称。

use Henzeb\Warmable\Illuminate\Warmable;
use DateTimeInterface;
use DateInterval;

class HeavyOperation extends Warmable
{
    protected function warmable(): mixed 
    {
         // ... your heavy operation
    }
}

依赖注入

Warmable Laravel 利用 Laravel 的依赖注入系统。它的工作方式与在 Controller 上解决依赖项的方式相似,因为它使用相同的实现。

use Henzeb\Warmable\Illuminate\Warmable;
use DateTimeInterface;
use DateInterval;

class HeavyOperation extends Warmable
{    
    protected function warmable(YourInjectedService $service): mixed 
    {
         // ... your heavy operation
    }
}

可以使用 with 方法注入依赖项,就像纯 Warmable 实现一样,额外的是你可以使用关联数组来注入自定义变量。

以下示例将注入 YourInjectedService 的实例,而不是使用应用程序容器解析新的实例。

HeavyOperation::with([
    'service' => new YourInjectedService()
]);

// The following however isn't possible:
HeavyOperation::with(
    [
        'service' => new YourInjectedService()
    ], 
    'another item'
);

注意:请注意,使用 with 注入的服务会改变键,使其唯一。有关更多信息,请参阅 Warmable

在构造函数中注入

你也可以像你习惯的那样在构造函数中注入依赖项。你不必使用 resolve 解析实例,因为 Warmable 在幕后使用 make 为你做了这件事。

use Henzeb\Warmable\Illuminate\Warmable;

class HeavyOperation extends Warmable {
    public function __construct(
    private YourService $yourService
    private YourOtherService $otherService
    ) {
    }
}

HeavyOperation::make();

HeavyOperation::make(['yourService' => new YourService()]);

get

get 方法的行为与其纯版本类似,但不同的是,当缓存项目尚不存在时,它将自身作为作业派发到队列,然后立即返回设置的默认值。像你习惯的那样,它接受可调用的默认值。

注意:如果将 connection 变量设置为 sync,它将立即创建缓存并返回其结果。当设置了默认值时,它将在向浏览器返回响应后执行此操作。

调度与队列

Warmable 是一个实现了 ShouldQueue 接口的 Job,这使得调度 Warmable 并将其发送到队列变得非常容易。

Warmable 是可调用的,允许您只需投入完全限定类名(FQCN),而无需回头再看。

$schedule->call(HeavyOperation::class)->daily(); // happens during execution
$schedule->job(HeavyOperation::class)->hourly(); // dispatches to the queue

注意:它还实现了 ShouldBeUnique 接口,这确保它不会同时运行两次。由于 Warmable 仅仅是一个作业,您可以进一步配置它。有关更多信息,请参阅 Laravel 文档。

确保缓存已预热

两者都会在预定时间预热缓存。但是,如果您需要确保缓存在缓存过期或丢失后立即预热,则可以使用 withPreheating,这将根据您的配置立即发送作业或调用,即使尚未达到指定的间隔。

$schedule->call(HeavyOperation::withPreheating())->daily();

// Will dispatch a job on the queue when preheating needs to happen
$schedule->job(HeavyOperation::withPreheating(true))->hourly();

注意:所有这一切的美丽之处在于,每当 Warmable 预热后,它都不会排队或执行任何操作。因此,它不会预热然后再预热。

预热

这是一个非常有用的特殊方法,当数据偶尔发生变化且需要尽快反映这些变化时。它将 Warmable 作为作业发送到队列。这允许用户继续前进,无需等待保存操作完成。

此方法返回一个 PendingDispatch 实例,允许您在实际发送之前修改配置。

HeavyOperation::preheat()->onQueue('sync');

事件

总共有 Warmable 发射 4 个不同的事件。事件名称应该可以说明它们何时被发射。

每个事件接收 keywarmable 作为 FQCN。除 CacheFailedWarmingUp 外,该事件接收实际实例以供调试目的。

CacheWarmedUp 还接收 result。这就是缓存中的内容。

使用自定义事件

可以使用实例变量更改每个事件。自定义事件仅由此 Warmable 发射。这允许您只需要监听特定 Warmable 的事件,而无需在监听器内部实现多个 ifmatch 语句。

use Henzeb\Warmable\Illuminate\Warmable;

class YourEvent {
    public function __construct(
        public string $key, // not required, the key of your Warmable
        public string $warmable // not required, FQCN of your Warmable
        public mixed $result = null // not required, only for CacheWarmedUp events
    ) {
    }
} 

class HeavyOperation extends Warmable {
    protected string $preheatingEvent = YourEvent::class;
    
    protected string $warmingUpEvent = YourEvent::class;
    
    protected string $failedWarmingUpEvent = YourEvent::class;
    
    protected string $warmedUpEvent = YourEvent::class;
} 

测试

composer test

贡献

请参阅CONTRIBUTING 获取详细信息。

安全

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

鸣谢

许可证

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