sofascore/purgatory

此包已被弃用且不再维护。作者建议使用 sofascore/purgatory-bundle 包。

用于简化构建缓存清除请求的库。

安装量: 15,014

依赖项: 0

建议者: 0

安全性: 0

星标: 43

关注者: 15

分支: 0

开放性问题: 16

类型:symfony-bundle

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

README

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

此包实现了一种简单且易于维护的方法,可以根据 Doctrine 实体的变化在端点上清除缓存。

安装

先决条件 - doctrine/orm

composer require sofascore/purgatory-bundle

设置 - Symfony 反向代理

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

framework:
  http_cache: true

将默认内核包装成 HttpCache 缓存内核 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。
  • 参数
    • 定义一个关联数组,其中键是路由参数,值是属性名称。
  • 属性
    • 需要更改以清除端点的属性列表。
    • 如果省略,则任何属性的变化都会清除缓存。
  • 如果
    • 一个表达式必须为真,以便使用指定的参数清除端点。

工作流程

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 并将实体属性与路由参数映射。当任何 Post 的属性更改时,注入实体 id 作为路由参数 postId 的端点无效。

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

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

使用 PurgeOn 并指定单个属性 - 每当任何 Posts 上的 featured 属性更改时,都会进行缓存无效化。

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

获取所有获得超过 3000 个点赞的受欢迎帖子的列表。

使用 PurgeOn 并指定条件 - 当具有超过 3000 个点赞的 Post 上的 upvotes 属性更改时,就会进行缓存无效化。

    /**
     * @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

请注意,点赞数的变化会导致热门帖子路径和帖子详情路径上的缓存失效。