sofascore/purgatory-bundle

用于轻松构建缓存清除请求的库。

安装次数: 11,403

依赖关系: 0

建议者: 0

安全: 0

星标: 48

关注者: 15

分支: 0

开放问题: 16

类型:symfony-bundle

v0.5.1 2023-06-21 09:47 UTC

This package is auto-updated.

Last update: 2024-09-30 10:13:55 UTC


README

Purgatory是一个扩展,它使得Symfony应用程序能够在最少的基础设施下处理巨大的负载。与该包以及Symfony应用程序一起使用的基础设施是HTTP缓存反向代理。

此包实现了一种简单且易于维护的方法,可以根据Doctrine实体的更改在端点处无效化缓存。

安装

先决条件 - doctrine/orm

composer require sofascore/purgatory-bundle

设置 - Symfony反向代理

config/packages/framework.yaml中启用Symfony Http Cache组件

framework:
  http_cache: true

将默认kernel包装进HttpCache缓存kernel public/index.php

<?php

use App\Kernel;
use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache;

require_once dirname(__DIR__).'/vendor/autoload_runtime.php';

return function (array $context) {
    return new HttpCache(new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']));
};

config/packages/purgatory中定义PurgerInterface的实现和清除的主机

purgatory:
  purger: 'sofascore.purgatory.purger.symfony'
  host: 'localhost:3000'

用法

假设您有一个简单的实体和控制器。

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity()
 * @ORM\Table(name="post1")
 */
class Post
{
    /**
     * @ORM\Id()
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue()
     */
    public $id;
    /**
     * @ORM\Column(type="string")
     */
    public $title;
    /**
     * @ORM\Column(type="string")
     */
    public $content;
}
namespace App\Controller;


use App\Entity\Post;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
 * @Route("/post")
 */
class PostController extends AbstractController
{

    public function __construct(private EntityManagerInterface $entityManager)
    {
    }

    /**
     * @Route("/{postId<\d+>}", methods={"GET"})
     */
    public function detailsAction(int $postId)
    {
        /** @var Post $post */
        $post = $this->entityManager->getRepository(Post::class)->find($postId);
        if (null === $post) {
            return new Response(status: 404);
        }

        $r = new Response(json_encode(['title' => $post->title, 'content'=>$post->content]), 200, []);
        $r->setSharedMaxAge(3600);
        $r->setMaxAge(3600);

        return $r;
    }
}

当第一次向端点发送请求时,反向代理会保存响应,并在此响应到期(本例中为1小时)之前提供相同的响应。如果在此期间实体的状态发生变化,网站上的内容将保持不变,直到缓存到期。

Purgatory有一个注解,当对象状态发生变化时,它定义了缓存无效化的规则。

use Sofascore\PurgatoryBundle\Annotation\PurgeOn;

    /**
    * @Route("/{postId<\d+>}", methods={"GET"})
    * @PurgeOn(Post::class, parameters={"postId":"id"}, properties={"title", "content"}, if="obj.title !== null")
    */ 
    public function indexAction(int $id) //...

PurgeOn注解

参数

  • 必需 被跟踪缓存清除的实体FQCN。
  • parameters
    • 定义一个关联数组,其中键是路由参数,值是属性名称。
  • properties
    • 需要更改以清除端点的属性列表。
    • 如果省略,则任何属性的变化都会清除缓存。
  • if
    • 一个表达式,必须为真才能清除具有指定参数的端点。

工作流程

Post实体的属性更改并刷新到数据库中时,Purgatory会遍历PurgeOn注解,其中更改的属性位于属性列表中,检查if表达式,注入参数,并清除路由。

自定义清除器

如果您有更复杂的设置或使用varnish(推荐),您应该实现自己的清除器,使其了解您的基础设施。

示例清除器

namespace App\Service;


use GuzzleHttp\Client;
use Sofascore\PurgatoryBundle\Purger\PurgerInterface;

class VarnishPurger implements PurgerInterface
{
    private Client $client;

    public function __construct()
    {
        $this->client = new Client();
    }

    public function purge(iterable $urls): void
    {
        foreach ($urls as $url) {
            $this->client->request('PURGE', 'http://varnish_host' . $url);
        }
    }
}

您还必须在配置中注册该清除器

purgatory:
  purger: App\Service\VarnishPurger

将清除功能添加到varnish

acl purge {
        "localhost";
        "172.0.0.0"/8; # if behind docker
        # add more whitelisted ips here
}

sub vcl_recv {
        if (req.method == "PURGE") {
                if (!client.ip ~ purge) {
                        return(synth(405,"Not allowed."));
                }
                return (purge);
        }
}

就这样!

示例

获取单个帖子所有属性的端点。

使用PurgeOn和FQCN,将路由参数映射到实体的属性。在Post的任何属性更改时,注入实体id作为路由参数postId的端点会失效。

    /**
     * @Route("/{postId<\d+>}", methods={"GET"})
     * @PurgeOn(Post::class, parameters={"postId":"id"})
     */
    public function detailsAction(int $postId) {

获取所有特色帖子的端点。

使用PurgeOn并指定单个属性 - 每当任何Postsfeatured属性更改时,都会发生缓存无效化。

    /**
     * @Route("/featured", methods={"GET"})
     * @PurgeOn(Post::class, properties={"featured"})
     */
    public function featuredAction() {

获取所有获得超过3000个赞的流行帖子的列表。

使用PurgeOn和条件 - 每当获得超过3000个赞的Postupvotes属性更改时,都会发生缓存无效化。

    /**
     * @Route("/popular", methods={"GET"})
     * @PurgeOn(Post::class, if="obj.upvotes > 3000")
     */
    public function popularAction(int $postId) {

调试

php bin/console purgatory:debug Post

地狱模式调试命令将所有定义的清理规则汇总并在屏幕上输出。它的参数是实体名称或实体及其属性。

php bin/console purgatory:debug Post::upvotes

定义了实体和属性的命令将输出所有由该属性变更而刷新的路由。

\App\Entity\Post
	app_post_details
		path: /post/{postId}
		parameters:
			postId: id

\App\Entity\Post::upvotes
	app_post_popular
		path: /post/popular
		if: obj.upvotes > 3000

请注意,点赞数的变更会导致热门帖子路由以及帖子详情路由的缓存失效。