From 7f8d4537bb797cc011f63c92ddb286c7a92a06ac Mon Sep 17 00:00:00 2001 From: Tim MacDonald Date: Wed, 21 Sep 2022 11:52:02 +1000 Subject: [PATCH 1/2] share WithoutOverlapping key across jobs --- .../Queue/Middleware/WithoutOverlapping.php | 18 ++++- .../Queue/WithoutOverlappingJobsTest.php | 81 +++++++++++++++++++ 2 files changed, 98 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Queue/Middleware/WithoutOverlapping.php b/src/Illuminate/Queue/Middleware/WithoutOverlapping.php index fe25c70db8f3..a9b85a81b5bd 100644 --- a/src/Illuminate/Queue/Middleware/WithoutOverlapping.php +++ b/src/Illuminate/Queue/Middleware/WithoutOverlapping.php @@ -38,6 +38,13 @@ class WithoutOverlapping */ public $prefix = 'laravel-queue-overlap:'; + /** + * Share the key across different jobs. + * + * @var bool + */ + public $shareKey = false; + /** * Create a new middleware instance. * @@ -128,6 +135,13 @@ public function withPrefix(string $prefix) return $this; } + public function shareKey() + { + $this->shareKey = true; + + return $this; + } + /** * Get the lock key for the given job. * @@ -136,6 +150,8 @@ public function withPrefix(string $prefix) */ public function getLockKey($job) { - return $this->prefix.get_class($job).':'.$this->key; + return $this->shareKey + ? $this->prefix.$this->key + : $this->prefix.get_class($job).':'.$this->key; } } diff --git a/tests/Integration/Queue/WithoutOverlappingJobsTest.php b/tests/Integration/Queue/WithoutOverlappingJobsTest.php index 1dded8c1185e..205142329462 100644 --- a/tests/Integration/Queue/WithoutOverlappingJobsTest.php +++ b/tests/Integration/Queue/WithoutOverlappingJobsTest.php @@ -112,6 +112,53 @@ public function testOverlappingJobsCanBeSkipped() $this->assertFalse(SkipOverlappingTestJob::$handled); } + + public function testCanShareKeyAcrossJobs() + { + OverlappingTestJobWithSharedKeyOne::$handled = false; + $instance = new CallQueuedHandler(new Dispatcher($this->app), $this->app); + + $lockKey = (new WithoutOverlapping)->shareKey()->getLockKey(new OverlappingTestJobWithSharedKeyTwo); + $this->app->get(Cache::class)->lock($lockKey, 10)->acquire(); + + $job = m::mock(Job::class); + + $job->shouldReceive('release')->once(); + $job->shouldReceive('hasFailed')->andReturn(false); + $job->shouldReceive('isReleased')->andReturn(true); + $job->shouldReceive('isDeletedOrReleased')->andReturn(true); + + $instance->call($job, [ + 'command' => serialize(new OverlappingTestJobWithSharedKeyOne), + ]); + + $this->assertFalse(OverlappingTestJob::$handled); + } + + public function testGetLock() + { + $job = new OverlappingTestJob; + + $this->assertSame( + 'laravel-queue-overlap:Illuminate\\Tests\\Integration\\Queue\\OverlappingTestJob:key', + (new WithoutOverlapping('key'))->getLockKey($job) + ); + + $this->assertSame( + 'laravel-queue-overlap:key', + (new WithoutOverlapping('key'))->shareKey()->getLockKey($job) + ); + + $this->assertSame( + 'prefix:Illuminate\\Tests\\Integration\\Queue\\OverlappingTestJob:key', + (new WithoutOverlapping('key'))->withPrefix('prefix:')->getLockKey($job) + ); + + $this->assertSame( + 'prefix:key', + (new WithoutOverlapping('key'))->withPrefix('prefix:')->shareKey()->getLockKey($job) + ); + } } class OverlappingTestJob @@ -148,3 +195,37 @@ public function handle() throw new Exception; } } + +class OverlappingTestJobWithSharedKeyOne +{ + use InteractsWithQueue, Queueable; + + public static $handled = false; + + public function handle() + { + static::$handled = true; + } + + public function middleware() + { + return [(new WithoutOverlapping)->shareKey()]; + } +} + +class OverlappingTestJobWithSharedKeyTwo +{ + use InteractsWithQueue, Queueable; + + public static $handled = false; + + public function handle() + { + static::$handled = true; + } + + public function middleware() + { + return [(new WithoutOverlapping)->shareKey()]; + } +} From 4e4da823d6c0fabfe7c0320047f32baf95596e4f Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 21 Sep 2022 09:18:07 -0500 Subject: [PATCH 2/2] formatting --- src/Illuminate/Queue/Middleware/WithoutOverlapping.php | 7 ++++++- tests/Integration/Queue/WithoutOverlappingJobsTest.php | 10 +++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Queue/Middleware/WithoutOverlapping.php b/src/Illuminate/Queue/Middleware/WithoutOverlapping.php index a9b85a81b5bd..2a37c3bd9569 100644 --- a/src/Illuminate/Queue/Middleware/WithoutOverlapping.php +++ b/src/Illuminate/Queue/Middleware/WithoutOverlapping.php @@ -135,7 +135,12 @@ public function withPrefix(string $prefix) return $this; } - public function shareKey() + /** + * Indicate that the lock key should be shared across job classes. + * + * @return void + */ + public function shared() { $this->shareKey = true; diff --git a/tests/Integration/Queue/WithoutOverlappingJobsTest.php b/tests/Integration/Queue/WithoutOverlappingJobsTest.php index 205142329462..049792f750df 100644 --- a/tests/Integration/Queue/WithoutOverlappingJobsTest.php +++ b/tests/Integration/Queue/WithoutOverlappingJobsTest.php @@ -118,7 +118,7 @@ public function testCanShareKeyAcrossJobs() OverlappingTestJobWithSharedKeyOne::$handled = false; $instance = new CallQueuedHandler(new Dispatcher($this->app), $this->app); - $lockKey = (new WithoutOverlapping)->shareKey()->getLockKey(new OverlappingTestJobWithSharedKeyTwo); + $lockKey = (new WithoutOverlapping)->shared()->getLockKey(new OverlappingTestJobWithSharedKeyTwo); $this->app->get(Cache::class)->lock($lockKey, 10)->acquire(); $job = m::mock(Job::class); @@ -146,7 +146,7 @@ public function testGetLock() $this->assertSame( 'laravel-queue-overlap:key', - (new WithoutOverlapping('key'))->shareKey()->getLockKey($job) + (new WithoutOverlapping('key'))->shared()->getLockKey($job) ); $this->assertSame( @@ -156,7 +156,7 @@ public function testGetLock() $this->assertSame( 'prefix:key', - (new WithoutOverlapping('key'))->withPrefix('prefix:')->shareKey()->getLockKey($job) + (new WithoutOverlapping('key'))->withPrefix('prefix:')->shared()->getLockKey($job) ); } } @@ -209,7 +209,7 @@ public function handle() public function middleware() { - return [(new WithoutOverlapping)->shareKey()]; + return [(new WithoutOverlapping)->shared()]; } } @@ -226,6 +226,6 @@ public function handle() public function middleware() { - return [(new WithoutOverlapping)->shareKey()]; + return [(new WithoutOverlapping)->shared()]; } }