Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitb14057c

Browse files
mpdudefabpot
authored andcommitted
Refactor stale-while-revalidate code in HttpCache, add a (first?) test for it
1 parent6b4cfd6 commitb14057c

File tree

3 files changed

+103
-36
lines changed

3 files changed

+103
-36
lines changed

‎src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php‎

Lines changed: 63 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -549,49 +549,39 @@ protected function lock(Request $request, Response $entry)
549549
// try to acquire a lock to call the backend
550550
$lock =$this->store->lock($request);
551551

552+
if (true ===$lock) {
553+
// we have the lock, call the backend
554+
returnfalse;
555+
}
556+
552557
// there is already another process calling the backend
553-
if (true !==$lock) {
554-
// check if we can serve the stale entry
555-
if (null ===$age =$entry->headers->getCacheControlDirective('stale-while-revalidate')) {
556-
$age =$this->options['stale_while_revalidate'];
557-
}
558558

559-
if (abs($entry->getTtl()) <$age) {
560-
$this->record($request,'stale-while-revalidate');
559+
// May we serve a stale response?
560+
if ($this->mayServeStaleWhileRevalidate($entry)) {
561+
$this->record($request,'stale-while-revalidate');
561562

562-
// server the stale response while there is a revalidation
563-
returntrue;
564-
}
565-
566-
// wait for the lock to be released
567-
$wait =0;
568-
while ($this->store->isLocked($request) &&$wait <5000000) {
569-
usleep(50000);
570-
$wait +=50000;
571-
}
563+
returntrue;
564+
}
572565

573-
if ($wait <5000000) {
574-
// replace the current entry with the fresh one
575-
$new =$this->lookup($request);
576-
$entry->headers =$new->headers;
577-
$entry->setContent($new->getContent());
578-
$entry->setStatusCode($new->getStatusCode());
579-
$entry->setProtocolVersion($new->getProtocolVersion());
580-
foreach ($new->headers->getCookies()as$cookie) {
581-
$entry->headers->setCookie($cookie);
582-
}
583-
}else {
584-
// backend is slow as hell, send a 503 response (to avoid the dog pile effect)
585-
$entry->setStatusCode(503);
586-
$entry->setContent('503 Service Unavailable');
587-
$entry->headers->set('Retry-After',10);
566+
// wait for the lock to be released
567+
if ($this->waitForLock($request)) {
568+
// replace the current entry with the fresh one
569+
$new =$this->lookup($request);
570+
$entry->headers =$new->headers;
571+
$entry->setContent($new->getContent());
572+
$entry->setStatusCode($new->getStatusCode());
573+
$entry->setProtocolVersion($new->getProtocolVersion());
574+
foreach ($new->headers->getCookies()as$cookie) {
575+
$entry->headers->setCookie($cookie);
588576
}
589-
590-
returntrue;
577+
}else {
578+
// backend is slow as hell, send a 503 response (to avoid the dog pile effect)
579+
$entry->setStatusCode(503);
580+
$entry->setContent('503 Service Unavailable');
581+
$entry->headers->set('Retry-After',10);
591582
}
592583

593-
// we have the lock, call the backend
594-
returnfalse;
584+
returntrue;
595585
}
596586

597587
/**
@@ -710,4 +700,41 @@ private function record(Request $request, $event)
710700
}
711701
$this->traces[$request->getMethod().''.$path][] =$event;
712702
}
703+
704+
/**
705+
* Checks whether the given (cached) response may be served as "stale" when a revalidation
706+
* is currently in progress.
707+
*
708+
* @param Response $entry
709+
*
710+
* @return bool True when the stale response may be served, false otherwise.
711+
*/
712+
privatefunctionmayServeStaleWhileRevalidate(Response$entry)
713+
{
714+
$timeout =$entry->headers->getCacheControlDirective('stale-while-revalidate');
715+
716+
if ($timeout ===null) {
717+
$timeout =$this->options['stale_while_revalidate'];
718+
}
719+
720+
returnabs($entry->getTtl()) <$timeout;
721+
}
722+
723+
/**
724+
* Waits for the store to release a locked entry.
725+
*
726+
* @param Request $request The request to wait for
727+
*
728+
* @return bool True if the lock was released before the internal timeout was hit; false if the wait timeout was exceeded.
729+
*/
730+
privatefunctionwaitForLock(Request$request)
731+
{
732+
$wait =0;
733+
while ($this->store->isLocked($request) &&$wait <5000000) {
734+
usleep(50000);
735+
$wait +=50000;
736+
}
737+
738+
return$wait <5000000;
739+
}
713740
}

‎src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,42 @@ public function testHitsCachedResponseWithMaxAgeDirective()
562562
$this->assertEquals('Hello World',$this->response->getContent());
563563
}
564564

565+
publicfunctiontestDegradationWhenCacheLocked()
566+
{
567+
$this->cacheConfig['stale_while_revalidate'] =10;
568+
569+
// The prescence of Last-Modified makes this cacheable (because Response::isValidateable() then).
570+
$this->setNextResponse(200,array('Cache-Control' =>'public, s-maxage=5','Last-Modified' =>'some while ago'),'Old response');
571+
$this->request('GET','/');// warm the cache
572+
573+
// Now, lock the cache
574+
$concurrentRequest = Request::create('/','GET');
575+
$this->store->lock($concurrentRequest);
576+
577+
/*
578+
* After 10s, the cached response has become stale. Yet, we're still within the "stale_while_revalidate"
579+
* timeout so we may serve the stale response.
580+
*/
581+
sleep(10);
582+
583+
$this->request('GET','/');
584+
$this->assertHttpKernelIsNotCalled();
585+
$this->assertEquals(200,$this->response->getStatusCode());
586+
$this->assertTraceContains('stale-while-revalidate');
587+
$this->assertEquals('Old response',$this->response->getContent());
588+
589+
/*
590+
* Another 10s later, stale_while_revalidate is over. Resort to serving the old response, but
591+
* do so with a "server unavailable" message.
592+
*/
593+
sleep(10);
594+
595+
$this->request('GET','/');
596+
$this->assertHttpKernelIsNotCalled();
597+
$this->assertEquals(503,$this->response->getStatusCode());
598+
$this->assertEquals('Old response',$this->response->getContent());
599+
}
600+
565601
publicfunctiontestHitsCachedResponseWithSMaxAgeDirective()
566602
{
567603
$time = \DateTime::createFromFormat('U',time() -5);

‎src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTestCase.php‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ class HttpCacheTestCase extends TestCase
2929
protected$responses;
3030
protected$catch;
3131
protected$esi;
32+
33+
/**
34+
* @var Store
35+
*/
3236
protected$store;
3337

3438
protectedfunctionsetUp()

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp