Skip to content

Commit 57bf892

Browse files
fix: CacheSchedulingMutex should use lock connection (#56472) (#56614)
Co-authored-by: Julius van Dijk <julius@anaglyphic.com>
1 parent c4cb071 commit 57bf892

File tree

2 files changed

+70
-4
lines changed

2 files changed

+70
-4
lines changed

src/Illuminate/Console/Scheduling/CacheSchedulingMutex.php

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
namespace Illuminate\Console\Scheduling;
44

55
use DateTimeInterface;
6+
use Illuminate\Cache\DynamoDbStore;
67
use Illuminate\Contracts\Cache\Factory as Cache;
8+
use Illuminate\Contracts\Cache\LockProvider;
79

810
class CacheSchedulingMutex implements SchedulingMutex, CacheAware
911
{
@@ -41,8 +43,16 @@ public function __construct(Cache $cache)
4143
*/
4244
public function create(Event $event, DateTimeInterface $time)
4345
{
46+
$mutexName = $event->mutexName().$time->format('Hi');
47+
48+
if ($this->shouldUseLocks($this->cache->store($this->store)->getStore())) {
49+
return $this->cache->store($this->store)->getStore()
50+
->lock($mutexName, 3600)
51+
->acquire();
52+
}
53+
4454
return $this->cache->store($this->store)->add(
45-
$event->mutexName().$time->format('Hi'), true, 3600
55+
$mutexName, true, 3600
4656
);
4757
}
4858

@@ -55,9 +65,26 @@ public function create(Event $event, DateTimeInterface $time)
5565
*/
5666
public function exists(Event $event, DateTimeInterface $time)
5767
{
58-
return $this->cache->store($this->store)->has(
59-
$event->mutexName().$time->format('Hi')
60-
);
68+
$mutexName = $event->mutexName().$time->format('Hi');
69+
70+
if ($this->shouldUseLocks($this->cache->store($this->store)->getStore())) {
71+
return ! $this->cache->store($this->store)->getStore()
72+
->lock($mutexName, 3600)
73+
->get(fn () => true);
74+
}
75+
76+
return $this->cache->store($this->store)->has($mutexName);
77+
}
78+
79+
/**
80+
* Determine if the given store should use locks for cache event mutexes.
81+
*
82+
* @param \Illuminate\Contracts\Cache\Store $store
83+
* @return bool
84+
*/
85+
protected function shouldUseLocks($store)
86+
{
87+
return $store instanceof LockProvider && ! $store instanceof DynamoDbStore;
6188
}
6289

6390
/**

tests/Console/Scheduling/CacheSchedulingMutexTest.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Illuminate\Tests\Console\Scheduling;
44

5+
use Illuminate\Cache\ArrayStore;
56
use Illuminate\Console\Scheduling\CacheEventMutex;
67
use Illuminate\Console\Scheduling\CacheSchedulingMutex;
78
use Illuminate\Console\Scheduling\Event;
@@ -52,13 +53,15 @@ protected function setUp(): void
5253

5354
public function testMutexReceivesCorrectCreate()
5455
{
56+
$this->cacheRepository->shouldReceive('getStore')->andReturn(new \stdClass);
5557
$this->cacheRepository->shouldReceive('add')->once()->with($this->event->mutexName().$this->time->format('Hi'), true, 3600)->andReturn(true);
5658

5759
$this->assertTrue($this->cacheMutex->create($this->event, $this->time));
5860
}
5961

6062
public function testCanUseCustomConnection()
6163
{
64+
$this->cacheRepository->shouldReceive('getStore')->andReturn(new \stdClass);
6265
$this->cacheFactory->shouldReceive('store')->with('test')->andReturn($this->cacheRepository);
6366
$this->cacheRepository->shouldReceive('add')->once()->with($this->event->mutexName().$this->time->format('Hi'), true, 3600)->andReturn(true);
6467
$this->cacheMutex->useStore('test');
@@ -68,22 +71,58 @@ public function testCanUseCustomConnection()
6871

6972
public function testPreventsMultipleRuns()
7073
{
74+
$this->cacheRepository->shouldReceive('getStore')->andReturn(new \stdClass);
7175
$this->cacheRepository->shouldReceive('add')->once()->with($this->event->mutexName().$this->time->format('Hi'), true, 3600)->andReturn(false);
7276

7377
$this->assertFalse($this->cacheMutex->create($this->event, $this->time));
7478
}
7579

7680
public function testChecksForNonRunSchedule()
7781
{
82+
$this->cacheRepository->shouldReceive('getStore')->andReturn(new \stdClass);
7883
$this->cacheRepository->shouldReceive('has')->once()->with($this->event->mutexName().$this->time->format('Hi'))->andReturn(false);
7984

8085
$this->assertFalse($this->cacheMutex->exists($this->event, $this->time));
8186
}
8287

8388
public function testChecksForAlreadyRunSchedule()
8489
{
90+
$this->cacheRepository->shouldReceive('getStore')->andReturn(new \stdClass);
8591
$this->cacheRepository->shouldReceive('has')->with($this->event->mutexName().$this->time->format('Hi'))->andReturn(true);
8692

8793
$this->assertTrue($this->cacheMutex->exists($this->event, $this->time));
8894
}
95+
96+
public function testMutexReceivesCorrectCreateWithLockProvider()
97+
{
98+
$this->cacheRepository->shouldReceive('getStore')->andReturn(new ArrayStore);
99+
100+
$this->assertTrue($this->cacheMutex->create($this->event, $this->time));
101+
}
102+
103+
public function testPreventsMultipleRunsWithLockProvider()
104+
{
105+
$this->cacheRepository->shouldReceive('getStore')->andReturn(new ArrayStore);
106+
107+
// first create the lock, so we can test that the next call fails.
108+
$this->cacheMutex->create($this->event, $this->time);
109+
110+
$this->assertFalse($this->cacheMutex->create($this->event, $this->time));
111+
}
112+
113+
public function testChecksForNonRunScheduleWithLockProvider()
114+
{
115+
$this->cacheRepository->shouldReceive('getStore')->andReturn(new ArrayStore);
116+
117+
$this->assertFalse($this->cacheMutex->exists($this->event, $this->time));
118+
}
119+
120+
public function testChecksForAlreadyRunScheduleWithLockProvider()
121+
{
122+
$this->cacheRepository->shouldReceive('getStore')->andReturn(new ArrayStore);
123+
124+
$this->cacheMutex->create($this->event, $this->time);
125+
126+
$this->assertTrue($this->cacheMutex->exists($this->event, $this->time));
127+
}
89128
}

0 commit comments

Comments
 (0)