为Zope 2应用程序提供缓存清除支持
项目描述
plone.cachepurging
简介
plone.cachepurging 包为 Zope 2 应用程序提供缓存清除功能。它受到(并从 Products.CMFSquidTool 中借用了一些代码)的启发,但它并不依赖于 Squid。事实上,它主要与 Varnish 进行测试,尽管它应该也可以与 Squid 和 Enfold Proxy 一起使用。
此包与 Plone 无关。但是,如果您打算与 Plone 一起使用它,您可能需要安装 plone.app.caching,它提供特定于 Plone 的配置和在 Plone 控制面板中的用户界面。
plone.cachepurging 与 Zope 2.12 及更高版本兼容。如果您想与 Zope 2.10 一起使用,您可能可以通过安装 ZPublisherEventsBackport 来实现,尽管这不是一个经过测试的配置。
安装
要使用此包,您必须执行以下操作
将其安装到您的 Zope 实例中。这通常意味着通过您的包的 setup.py 文件中的 install_requires 依赖于它。
通过添加以下类似的 ZCML 行(或一个别名)来加载其配置
<include package="plone.cachepurging" />
安装一个 plone.registry IRegistry 本地实用工具,并为接口 plone.cachepurging.interfaces.ICachePurgingSettings 创建记录。有关详细信息,请参阅 plone.registry 文档。
如果您在 Plone 中使用 plone.app.caching,它将为您完成所有这些。
要在安装后启用缓存清除,您必须
设置一个支持 PURGE 请求的缓存代理,例如 Varnish、Squid 或 Enfold Proxy。
配置代理和您的应用程序,以便资源在代理中缓存。
将注册选项 plone.cachepurging.interfaces.ICachePurgingSettings.enabled 设置为 True。有关详细信息,请参阅 plone.registry 文档。
将至少一个能够接收 PURGE 请求的缓存代理服务器的 URL 添加到注册选项 plone.cachepurging.interfaces.ICachePurgingSettings.cachingProxies 中。这应该是一个从 Zope 服务器可访问的 URL。它不需要从 Zope 的客户端可访问。
使您的应用程序发送清除通知 - 请参阅下文。
在代码中启动清除
启动清除的最简单方法是引发一个 Purge 事件
from z3c.caching.purge import Purge from zope.event import notify notify(Purge(context))
注意我们实际上是从 z3c.caching 中导入的。这个包定义了事件类型和几个 plone.cachepurging 所使用的接口。在大多数情况下,您应该能够通过仅依赖于 z3c.caching 来定义您自己的包相对于缓存代理的行为。这是一个更安全的依赖关系,因为它反过来只依赖于少量核心 Zope 工具包。
假设 plone.cachepurging 已经安装,触发上述事件将
检查缓存是否启用并配置。如果没有,它将不执行任何操作。
查找要清除给定对象的路径。这是通过零个或多个 IPurgePaths 适配器完成的。请参阅下面的“哪些 URL 被清除?”
通过将它们与配置的缓存代理的 URL 结合起来,将这些清除路径转换为 URL。
将这些路径排队以进行清除。
如果某个特定对象或 URL 被排队长达一次,这无关紧要。它只会执行一次。
此操作相对较快,不涉及与缓存代理的通信。在请求结束时,在 Zope 事务关闭之后(假设事务成功 - 默认情况下,不会为导致错误的请求执行清除),将发生以下情况
从请求中检索排队的 URL。
为每个缓存代理建立了一个工作线程,允许异步处理并释放 Zope 处理下一个请求。
工作线程建立与缓存代理的连接并发送一个 PURGE 请求。
任何错误都以错误级别记录到 plone.cachepurging 记录器。
如果您需要更多控制,可以直接执行清除。以下是从 plone.cachepurging.purge 观看中改编的一段代码
from io import StringIO from zope.component import getUtility from plone.registry.interfaces import IRegistry from plone.cachepurging.interfaces import IPurger from plone.cachepurging.interfaces import ICachePurgingSettings from plone.cachepurging.utils import getPathsToPurge from plone.cachepurging.utils import getURLsToPurge from plone.cachepurging.utils import isCachePurgingEnabled ... if not isCachePurgingEnabled(): return 'Caching not enabled' registry = getUtility(IRegistry) settings = registry.forInterface(ICachePurgingSettings) purger = getUtility(IPurger) out = StringIO() for path in getPathsToPurge(self.context, self.request): for url in getURLsToPurge(path, settings.cachingProxies): status, xcache, xerror = purger.purgeSync(url) print("Purged", url, "Status", status, "X-Cache", xcache, "Error:", xerror, file=out) return out.getvalue()
在这里,我们
检查缓存是否启用。这检查注册表中的 enabled 和 cachingProxies 属性。
查找注册表和缓存清除设置以找到缓存代理的列表。
获取一个 IPurger 实用工具。这有三个主要方法
def purgeAsync(url, httpVerb='PURGE'): """Send a PURGE request to a particular URL asynchronously in a worker thread. """ def purgeSync(url, httpVerb='PURGE'): """Send a PURGE request to a particular URL synchronosly. Returns a triple ``(status, xcache, xerror)`` where ``status`` is the HTTP status of the purge request, ``xcache`` is the contents of the ``x-cache`` response header, and ``x-error`` is the contents of the first header found from the list of headers in ``errorHeaders``. """ def stopThreads(wait=False): """Attempts to stop all threads. Threads stop immediately after the current item is being processed. Returns True if successful, or False if threads are still running after waiting 5 seconds for each one. """
使用辅助函数 getPathsToPurge() 获取当前上下文的所有清除路径。路径相对于域名根,即以一个 ‘/’ 开头。
使用辅助函数 getURLsToPurge() 获取每个缓存代理的完整 PURGE URL。
发送一个同步缓存请求。这将阻塞,直到缓存代理响应(或超时)。
手动清除对象
上面的代码说明了如何启动异步和同步清除。如果您只想通过 Web 执行此操作,可以调用以下已注册的任何类型上下文的一个视图
- @@plone.cachepurging.purge
执行与上面显示的代码类似的上下文即时清除。
- @@plone.cachepurging.queue
将上下文排队以进行清除。
这两个视图都需要 plone.cachepurging.InitiatePurge 权限,该权限默认仅授予 Manager 角色。
自动清除对象
通常,您会在以下三种情况下清除对象
当对象被修改时
当对象被移动或重命名时
当对象被删除时
这些都是由 zope.lifecycleevent 包的标准 Zope 事件类型描述的。如果为您的上下文触发了标准的 IObjectModifiedEvent、IObjectMovedEvent 和 IObjectRemovedEvent 事件类型,您可以标记它以使用 IPurgeable 接口自动清除对象。
不更改您的内容对象代码的一种方法是使用 ZCML 执行此操作,例如
<class class=".content.MyContent"> <implements interface="z3c.caching.interfaces.IPurgeable" /> </class>
(再次注意我们是如何从 z3c.caching 使用通用接口的)。
这相当于为上述每个事件注册一个事件处理器,并在每个事件中执行 notify(Purge(object))。也就是说,一个 z3c.caching.interfaces.IPurgeEvent 将在生命周期事件的处理器中被触发,从而引发清理过程。
清除依赖项
有时,清理一个对象意味着其他对象也需要被清理。一种方法是注册一个针对 IPurgeEvent 事件类型的事件处理器,并响应地分派进一步的清理事件。例如,以下是一些清理被清理对象父对象的代码:
from zope.component import adapter from z3c.caching.interfaces import IPurgeEvent from z3c.caching.purge import Purge @adapter(IMyContent, IPurgeEvent) def purgeParent(object, IPurgeEvent): parent = object.__parent__ if parent is not None: notify(Purge(parent))
这可以在 ZCML 中注册如下:
<subscriber handler=".events.purgeParent" />
如果父对象也是 IMyContent 类型(或者用更通用的接口替换),那么它的父对象也会被递归地清理。
哪些 URL 会清除?
Purge 事件处理器通过命名的 z3c.caching.interfaces.IPurgePaths 适配器计算要清理的对象的 URL。可以注册任意数量的此类适配器。plone.cachepurging 随带一个适配器,用于 OFS.interfaces.ITraversable(即大多数可以通过 ZMI 找到的对象),它清理对象的 absolute_url_path()。
IPurgePaths 接口看起来如下:
class IPurgePaths(Interface): """Return paths to send as PURGE requests for a given object. The purging hook will look up named adapters from the objects sent to the purge queue (usually by an IPurgeEvent being fired) to this interface. The name is not significant, but is used to allow multiple implementations whilst still permitting per-type overrides. The names should therefore normally be unique, prefixed with the dotted name of the package to which they belong. """ def getRelativePaths(): """Return a list of paths that should be purged. The paths should be relative to the virtual hosting root, i.e. they should start with a '/'. These paths will be rewritten to incorporate virtual hosting if necessary. """ def getAbsolutePaths(): """Return a list of paths that should be purged. The paths should be relative to the domain root, i.e. they should start with a '/'. These paths will *not* be rewritten to incorporate virtual hosting. """
大多数实现都会使用 getRelativePaths() 来返回相对于虚拟主机根的路径(即 absolute_url_path() 方法返回的内容)。这可能会因为虚拟主机而需要重写(见下文)。
getAbsolutePaths() 对于那些无论 Zope 如何配置都不会变化的路径很有用。例如,如果您的缓存代理支持“特殊”URL以调用特定的清理类型,您可以使用此功能。(例如,这种行为可以在 Varnish 中使用 VCL 实现。)这不适用于虚拟主机重写。
假设您想要始终清理来自 CMF 的提供 IContentish 的任何对象的 URL ${object_url}/view。一个简单的实现可能如下所示:
from zope.interface import implementer from zope.component import adapts from z3c.caching.interfaces import IPurgePaths from Products.CMFCore.interfaces import IContentish @implementer(IPurgePaths) class ObjectViewPurgePaths(object): """Purge /view for any content object with the content object's default URL """ adapts(IContentish) def __init__(self, context): self.context = context def getRelativePaths(self): return [self.context.absolute_url_path() + '/view'] def getAbsolutePaths(self): return []
此适配器可以通过以下 ZCML 语句进行注册:
<adapter factory=".paths.ObjectViewPurgePaths" name="my.package.objectview" />
名称并不重要,但应该是唯一的,除非您打算覆盖现有的适配器。按照惯例,除非您有理由不这样做,否则应该使用您的包的点分名称作为前缀。
简单地返回 absolute_url_path() 的默认适配器称为 default。
虚拟主机和 URL 转写
Zope 2 使用“魔法”URL 进行虚拟主机。一个常见场景是将虚拟主机根设置为 Zope 实例根部的 Plone 站点对象。这通常通过 URL 重写来完成。用户看到一个类似于 http://example.com/front-page 的 URL。像 Apache(或 Squid 或 Varnish 这样的)Web 服务器将其更改为如下 URL:
https://127.0.0.1:8080/VirtualHostBase/http/example.com:80/Plone/VirtualHostRoot/front-page
在这里,Zope 服务器运行在 https://127.0.0.1:8080,外部域名是 http://example.com:80(:80 部分通常不会被 Web 浏览器显示,因为这是 http URL 方案默认的协议),虚拟主机根是 /Plone。
Zope会在URL中识别这些标记,并理解如何将外部域名和虚拟主机根目录合并到诸如absolute_url()和absolute_url_path()等方法的输出结果中,从而使得网站生成的URL能够显示正确的外部URL。
到目前为止一切顺利。但是,当你将缓存代理加入到系统中时,就会遇到挑战。这里有两种情况
缓存代理位于URL重写操作的“后方”。在这种情况下,入站URL(代理可能会选择缓存,因此可能需要清除)包含了虚拟主机标记。
缓存代理位于URL重写操作的“前方”,或者在进行请求转发到Zope后端之前先进行重写。在这种情况下,入站URL不包含虚拟主机标记。
清除操作通过向代理服务器发送与缓存资源路径相同的PURGE请求来实现。因此,在第一种情况下,该URL需要包含虚拟主机标记。由于这些标记不是Zope生成的任何URL的一部分(尽管它们保留在PATH_INFO请求变量中),因此需要重写IPurgePaths适配器的返回路径(可以说是反向重写),以包含它们。
这通过在请求上使用IPurgePathRewriter适配器来实现。默认实现将处理任何有效的VirtualHostMonster URL,包括使用“内外”主机(带有_vh_类型路径段)的设置,尽管如果您有独特的需求,也可以编写自己的适配器。
如果您在缓存代理前方执行URL重写(如上述第一种情况),则需要配置两个注册选项,因为plone.cachepurging无法知道Zope前方配置的Web和/或代理缓存服务器
- plone.cachepurging.interfaces.ICachePurgingSettings.virtualHosting
将其设置为True以在清除路径中包含虚拟主机标记。这适用于上述第一种情况。
- plone.cachepurging.interfaces.ICachePurgingSettings.domains
如果您的网站在多个域名上提供服务,请将此设置为包含端口的域名元组(例如('http://example.com:80`, 'http://www.example.com:80',))。这很有用,因为虚拟主机URL包含“外部”域名。如果您的网站可以通过多个域名访问(例如http://example.com与http://www.example.com),则虚拟主机路径将根据用户使用的不同而不同。很可能会想要清除两种变体。
请注意,最好在网关Web服务器中规范化路径,这样Zope就只能看到单个外部域名。如果您只有一个域名,或者如果virtualHosting选项为false,则不需要设置此选项。
变更日志
3.0.2 (2023-10-07)
内部
更新配置文件。[plone开发者](cfffba8c)
3.0.1 (2023-03-14)
内部
更新配置文件。[plone开发者](359b1152)
3.0.0 (2022-11-30)
错误修复
最终发布。[gforcada](#600)
3.0.0a1 (2022-05-15)
破坏性更改
取消Python 2支持。代码风格。[jensens](#26)
2.0.4 (2021-12-29)
错误修复
通过增强清除视图@@plone.cachepurging.purge和@@plone.cachepurging.queue的输出,提高了调试能力。[jensens](#21)
2.0.3 (2021-03-02)
错误修复
替换了已废弃的Thread.isAlive为is_alive。旧名称在Python 3.9中不再工作。新名称已经在Python 2.7中工作。(#22)
2.0.2 (2020-04-20)
错误修复
较小的打包更新。(#1)
2.0.1 (2018-12-11)
破坏性更改
删除five.globalrequest依赖。它已被上游(Zope 4)弃用。[gforcada]
错误修复
避免资源警告:未关闭的套接字。[gforcada]
2.0 (2018-10-31)
破坏性更改
使用requests库代替我们自己手动创建连接和请求。这可以避免在现实客户环境中出现奇怪的问题。在这里我们不需要重新发明轮子。Requests总是使用HTTP 1.1,并停止对HTTP 1.0仅缓存的支持。[jensens]
新功能
尝试在运行测试时避免端口冲突。[gforcada]
错误修复
将默认的清理器回压大小设置为0(无限大),以便完全使Varnish缓存失效。[avoinea refs #11]
测试和代码与Python 3兼容。[pbauer, ale-rt, jensens]
1.0.15 (2018-04-24)
错误修复
考虑当它被启用时启用清理(即使没有列出服务器)[skurfer]
1.0.14 (2018-01-30)
错误修复
添加Python 2/3兼容性。[pbauer]
1.0.13 (2016-10-04)
错误修复
代码风格:isort, utf8-headers, zca-decorators, 手动清理。[jensens]
1.0.12 (2016-08-08)
新功能
使用zope.interface装饰器。[gforcada]
1.0.11 (2016-01-08)
修复
修复了错别字。[ale-rt]
1.0.10 (2015-11-28)
修复
将i18n_domain更改为“plone”。[staeff]
1.0.9 (2015-07-18)
在没有设置缓存代理时不要迭代settings.cachingProxies。[gotcha]
1.0.8 (2015-06-09)
正确地能够清理空路径(网站的根目录)。以前,总是将/附加到url上,所以资源的一个潜在路径在varnish中永远不会被清理——有时是最重要的,主页。[vangheem]
1.0.7 (2014-09-11)
修复由于setup.py中缺少逗号导致的安装问题。[esteele]
1.0.6 (2014-09-08)
添加未声明的依赖项。[gforcada]
1.0.5 (2013-12-07)
替换过时的测试断言语句。[timo]
1.0.4 (2012-12-09)
修复了使用虚拟路径组件的虚拟主机场景中的清理路径。[dokai]
1.0.3 (2011-09-16)
仅在清理HTTPS URL时导入ssl模块,关闭#12190。[elro]
1.0.2 (2011-08-31)
在调用xrange之前将wait_time转换为int。这修复了“TypeError:期望整数参数,但得到浮点数”错误。[vincentfretin]
1.0.1 - 2011-05-21
注册一个zope.testing.cleanup.addCleanUp函数来停止所有清理线程。同时使默认清理器作为模块全局可用,以便清理函数在ZCA被拆解后可以访问它。[hannosch]
注册一个atexit处理程序,在进程关闭时停止清理线程。[hannosch]
将清理线程的重连策略更改为尝试更少的次数,并在一分钟后将永久连接故障视为假设,并停止线程。这允许应用程序进程干净地关闭,而清理线程不会永远卡住。[hannosch]
更新清理线程的套接字连接代码以使用Python 2.6对create_connection调用传递超时的支持。[hannosch]
在调试模式下禁用清理队列已满警告,它会垃圾邮件式地填充控制台。[hannosch]
纠正许可证并更新发行版元数据。[hannosch]
1.0 - 2011-05-13
发布1.0最终版。[esteele]
添加MANIFEST.in。[WouterVH]
1.0b2 - 2011-04-06
修复包需求,以便在[测试]额外组件中拉取plone.app.testing。[esteele]
1.0b1 - 2010-12-14
修复虚拟主机环境中路径重写的错误,以便将传递给重写器的路径实际上被使用,而不是总是使用当前请求路径。[davisagli]
1.0a1 - 2010-04-22
初始发布 [optilude, newbery]
项目详情
plone.cachepurging-3.0.2.tar.gz的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 9f770e2861a57f9a70af1699bef6a970d15e99ba5293034b93bb0bdb5f783782 |
|
MD5 | a20a3ca8716f42c8cf29d9156fc9d2e7 |
|
BLAKE2b-256 | b5be7fe78f064e76b8eb6efe234d3debcd80ef0bcf67f53e14fcf747a3bd66e6 |
plone.cachepurging-3.0.2-py3-none-any.whl的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | ae27366d1170fa71d676fecfa790c99bed34f308cb2b047b356bea2a70387e42 |
|
MD5 | 5ff41fb3697404e343eca0e530befe3e |
|
BLAKE2b-256 | 2494a454d4eb50a8dfc99a6026204c47e65624222808c9597b361f355816a114 |