Skip to content

Commit 1152edf

Browse files
committed
feature #60498 [HttpCache] Add a waiting trace when finding the cache locked (mpdude)
This PR was squashed before being merged into the 7.4 branch. Discussion ---------- [HttpCache] Add a `waiting` trace when finding the cache locked | Q | A | ------------- | --- | Branch? | 7.3 | Bug fix? | no | New feature? | yes | Deprecations? | no | Issues | | License | MIT This adds a new `waiting` trace that will be recorded by the `HttpCache` when the cache had to wait for another, concurrent request to the same resource to finish first. The information can be used for profiling - a high rate of `waiting` requests means there is a lot of concurrency, so that it might be beneficial to either speed up request processing or consider using `stale-while-revalidate`. Commits ------- 79d8097 [HttpCache] Add a `waiting` trace when finding the cache locked
2 parents 8c89e4c + 79d8097 commit 1152edf

File tree

4 files changed

+41
-3
lines changed

4 files changed

+41
-3
lines changed

src/Symfony/Component/HttpKernel/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ CHANGELOG
44
7.3
55
---
66

7+
* Record a `waiting` trace in the `HttpCache` when the cache had to wait for another request to finish
78
* Add `$key` argument to `#[MapQueryString]` that allows using a specific key for argument resolving
89
* Support `Uid` in `#[MapQueryParameter]`
910
* Add `ServicesResetterInterface`, implemented by `ServicesResetter`
1011
* Allow configuring the logging channel per type of exceptions in ErrorListener
11-
12+
1213
7.2
1314
---
1415

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,8 @@ protected function lock(Request $request, Response $entry): bool
558558
return true;
559559
}
560560

561+
$this->record($request, 'waiting');
562+
561563
// wait for the lock to be released
562564
if ($this->waitForLock($request)) {
563565
// replace the current entry with the fresh one

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Symfony\Component\HttpKernel\Event\TerminateEvent;
1818
use Symfony\Component\HttpKernel\HttpCache\Esi;
1919
use Symfony\Component\HttpKernel\HttpCache\HttpCache;
20+
use Symfony\Component\HttpKernel\HttpCache\Store;
2021
use Symfony\Component\HttpKernel\HttpCache\StoreInterface;
2122
use Symfony\Component\HttpKernel\HttpKernelInterface;
2223
use Symfony\Component\HttpKernel\Kernel;
@@ -662,6 +663,7 @@ public function testDegradationWhenCacheLocked()
662663
*/
663664
sleep(10);
664665

666+
$this->store = $this->createStore(); // create another store instance that does not hold the current lock
665667
$this->request('GET', '/');
666668
$this->assertHttpKernelIsNotCalled();
667669
$this->assertEquals(200, $this->response->getStatusCode());
@@ -680,6 +682,32 @@ public function testDegradationWhenCacheLocked()
680682
$this->assertEquals('Old response', $this->response->getContent());
681683
}
682684

685+
public function testTraceAddedWhenCacheLocked()
686+
{
687+
if ('\\' === \DIRECTORY_SEPARATOR) {
688+
$this->markTestSkipped('Skips on windows to avoid permissions issues.');
689+
}
690+
691+
// Disable stale-while-revalidate, which circumvents blocking access
692+
$this->cacheConfig['stale_while_revalidate'] = 0;
693+
694+
// The presence of Last-Modified makes this cacheable
695+
$this->setNextResponse(200, ['Cache-Control' => 'public, no-cache', 'Last-Modified' => 'some while ago'], 'Old response');
696+
$this->request('GET', '/'); // warm the cache
697+
698+
$primedStore = $this->store;
699+
700+
$this->store = $this->createMock(Store::class);
701+
$this->store->method('lookup')->willReturnCallback(fn (Request $request) => $primedStore->lookup($request));
702+
// Assume the cache is locked at the first attempt, but immediately treat the lock as released afterwards
703+
$this->store->method('lock')->willReturnOnConsecutiveCalls(false, true);
704+
$this->store->method('isLocked')->willReturn(false);
705+
706+
$this->request('GET', '/');
707+
708+
$this->assertTraceContains('waiting');
709+
}
710+
683711
public function testHitsCachedResponseWithSMaxAgeDirective()
684712
{
685713
$time = \DateTimeImmutable::createFromFormat('U', time() - 5);

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ abstract class HttpCacheTestCase extends TestCase
3030
protected $responses;
3131
protected $catch;
3232
protected $esi;
33-
protected Store $store;
33+
protected ?Store $store = null;
3434

3535
protected function setUp(): void
3636
{
@@ -115,7 +115,9 @@ public function request($method, $uri = '/', $server = [], $cookies = [], $esi =
115115

116116
$this->kernel->reset();
117117

118-
$this->store = new Store(sys_get_temp_dir().'/http_cache');
118+
if (!$this->store) {
119+
$this->store = $this->createStore();
120+
}
119121

120122
if (!isset($this->cacheConfig['debug'])) {
121123
$this->cacheConfig['debug'] = true;
@@ -183,4 +185,9 @@ public static function clearDirectory($directory)
183185

184186
closedir($fp);
185187
}
188+
189+
protected function createStore(): Store
190+
{
191+
return new Store(sys_get_temp_dir().'/http_cache');
192+
}
186193
}

0 commit comments

Comments
 (0)