sofascore / purgatory
Requires
- php: >=8.1
- doctrine/annotations: ^1.13 || ^2
- doctrine/doctrine-bundle: ^2.1
- doctrine/orm: ^2.8
- symfony/config: ^5.4 || ^6.2
- symfony/console: ^5.4 || ^6.2
- symfony/dependency-injection: ^5.4 || ^6.2
- symfony/expression-language: ^5.4 || ^6.2
- symfony/http-kernel: ^5.4 || ^6.2
- symfony/property-access: ^5.4 || ^6.2
- symfony/routing: ^5.4 || ^6.2
Requires (Dev)
- symfony/framework-bundle: ^5.4 || ^6.2
- symfony/phpunit-bridge: ^6.2
- symfony/serializer: ^5.4 || ^6.2
This package is auto-updated.
Last update: 2024-04-30 09:20:10 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
请注意,点赞数的变化会导致热门帖子路径和帖子详情路径上的缓存失效。