From 4a3e3c95b387c5f1212d6d7dee4b9e5294cfb7a6 Mon Sep 17 00:00:00 2001 From: Aaron Schulz Date: Mon, 22 Aug 2016 21:10:13 -0700 Subject: [PATCH] Use adaptive CDN TTLs for page views This makes frequently changed pages be less likely to be seen in stale forms if purges are delayed or lost. Pages that have not been edited for somewhat longer than the nominal CDN cache TTL will retain the nominal TTL. Category pages will adapt based on page_touched rather than the last revision, given the possibility of constaintly changing membership. With their lesser overall usage, this is less risky than for Article, and also more useful. Change-Id: If621aca2fb68e9f87a50c891dac8dc6ec7641f5c --- includes/OutputPage.php | 30 ++++++++++++++++++++++++++++++ includes/page/Article.php | 5 ++++- includes/page/CategoryPage.php | 4 ++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/includes/OutputPage.php b/includes/OutputPage.php index c7499b1b45..48e6cc42b8 100644 --- a/includes/OutputPage.php +++ b/includes/OutputPage.php @@ -1938,6 +1938,36 @@ class OutputPage extends ContextSource { $this->setCdnMaxage( $this->mCdnMaxage ); } + /** + * Get TTL in [$minTTL,$maxTTL] in pass it to lowerCdnMaxage() + * + * This sets and returns $minTTL if $mtime is false or null. Otherwise, + * the TTL is higher the older the $mtime timestamp is. Essentially, the + * TTL is 90% of the age of the object, subject to the min and max. + * + * @param string|integer|float|bool|null $mtime Last-Modified timestamp + * @param integer $minTTL Mimimum TTL in seconds [default: 1 minute] + * @param integer $maxTTL Maximum TTL in seconds [default: $wgSquidMaxage] + * @return integer TTL in seconds + * @since 1.28 + */ + public function adaptCdnTTL( $mtime, $minTTL = 0, $maxTTL = 0 ) { + $minTTL = $minTTL ?: IExpiringStore::TTL_MINUTE; + $maxTTL = $maxTTL ?: $this->getConfig()->get( 'SquidMaxage' ); + + if ( $mtime === null || $mtime === false ) { + return $minTTL; // entity does not exist + } + + $age = time() - wfTimestamp( TS_UNIX, $mtime ); + $adaptiveTTL = max( .9 * $age, $minTTL ); + $adaptiveTTL = min( $adaptiveTTL, $maxTTL ); + + $this->lowerCdnMaxage( (int)$adaptiveTTL ); + + return $adaptiveTTL; + } + /** * Use enableClientCache(false) to force it to send nocache headers * diff --git a/includes/page/Article.php b/includes/page/Article.php index 6396aaabcf..3f882a2c4c 100644 --- a/includes/page/Article.php +++ b/includes/page/Article.php @@ -717,6 +717,10 @@ class Article implements Page { } } + # Use adaptive TTLs for CDN so delayed/failed purges are noticed less often. + # This could use getTouched(), but that could be scary for major template edits. + $outputPage->adaptCdnTTL( $this->mPage->getTimestamp(), IExpiringStore::TTL_DAY ); + # Check for any __NOINDEX__ tags on the page using $pOutput $policy = $this->getRobotPolicy( 'view', $pOutput ); $outputPage->setIndexPolicy( $policy['index'] ); @@ -726,7 +730,6 @@ class Article implements Page { $this->mPage->doViewUpdates( $user, $oldid ); $outputPage->addModules( 'mediawiki.action.view.postEdit' ); - } /** diff --git a/includes/page/CategoryPage.php b/includes/page/CategoryPage.php index d493002684..4a9288ec8d 100644 --- a/includes/page/CategoryPage.php +++ b/includes/page/CategoryPage.php @@ -80,6 +80,10 @@ class CategoryPage extends Article { if ( $title->inNamespace( NS_CATEGORY ) ) { $this->closeShowCategory(); } + + # Use adaptive TTLs for CDN so delayed/failed purges are noticed less often + $outputPage = $this->getContext()->getOutput(); + $outputPage->adaptCdnTTL( $this->mPage->getTouched(), IExpiringStore::TTL_MINUTE ); } function openShowCategory() { -- 2.20.1