Skip to content

Commit d20d7ef

Browse files
[9.x] Add unique locking to broadcast events (#43416)
* Add unique locking to broadcast events * Don't require uniqueId, set default * Locking irrelevant when broadcasting now * formatting Co-authored-by: Taylor Otwell <[email protected]>
1 parent c73d856 commit d20d7ef

File tree

4 files changed

+103
-1
lines changed

4 files changed

+103
-1
lines changed

src/Illuminate/Broadcasting/BroadcastManager.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use Illuminate\Broadcasting\Broadcasters\PusherBroadcaster;
1212
use Illuminate\Broadcasting\Broadcasters\RedisBroadcaster;
1313
use Illuminate\Contracts\Broadcasting\Factory as FactoryContract;
14+
use Illuminate\Contracts\Broadcasting\ShouldBeUnique;
1415
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
1516
use Illuminate\Contracts\Bus\Dispatcher as BusDispatcherContract;
1617
use Illuminate\Contracts\Foundation\CachesRoutes;
@@ -166,7 +167,10 @@ public function queue($event)
166167
}
167168

168169
$this->app->make('queue')->connection($event->connection ?? null)->pushOn(
169-
$queue, new BroadcastEvent(clone $event)
170+
$queue,
171+
$event instanceof ShouldBeUnique
172+
? new UniqueBroadcastEvent(clone $event)
173+
: new BroadcastEvent(clone $event)
170174
);
171175
}
172176

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
3+
namespace Illuminate\Broadcasting;
4+
5+
use Illuminate\Contracts\Queue\ShouldBeUnique;
6+
7+
class UniqueBroadcastEvent extends BroadcastEvent implements ShouldBeUnique
8+
{
9+
/**
10+
* The unique lock identifier.
11+
*
12+
* @var mixed
13+
*/
14+
public $uniqueId;
15+
16+
/**
17+
* The number of seconds the unique lock should be maintained.
18+
*
19+
* @var int
20+
*/
21+
public $uniqueFor;
22+
23+
/**
24+
* The cache repository implementation that should be used to obtain unique locks.
25+
*
26+
* @var \Illuminate\Contracts\Cache\Repository
27+
*/
28+
public $uniqueVia;
29+
30+
/**
31+
* Create a new job handler instance.
32+
*
33+
* @param mixed $event
34+
* @return void
35+
*/
36+
public function __construct($event)
37+
{
38+
$this->uniqueId = get_class($event);
39+
40+
if (method_exists($event, 'uniqueId')) {
41+
$this->uniqueId = $event->uniqueId();
42+
} elseif (property_exists($event, 'uniqueId')) {
43+
$this->uniqueId = $event->uniqueId;
44+
}
45+
46+
if (method_exists($event, 'uniqueFor')) {
47+
$this->uniqueFor = $event->uniqueFor();
48+
} elseif (property_exists($event, 'uniqueFor')) {
49+
$this->uniqueFor = $event->uniqueFor;
50+
}
51+
52+
if (method_exists($event, 'uniqueVia')) {
53+
$this->uniqueVia = $event->uniqueVia();
54+
} elseif (property_exists($event, 'uniqueVia')) {
55+
$this->uniqueVia = $event->uniqueVia;
56+
}
57+
58+
parent::__construct($event);
59+
}
60+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace Illuminate\Contracts\Broadcasting;
4+
5+
interface ShouldBeUnique
6+
{
7+
//
8+
}

tests/Integration/Broadcasting/BroadcastManagerTest.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33
namespace Illuminate\Tests\Integration\Broadcasting;
44

55
use Illuminate\Broadcasting\BroadcastEvent;
6+
use Illuminate\Broadcasting\UniqueBroadcastEvent;
7+
use Illuminate\Contracts\Broadcasting\ShouldBeUnique;
68
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
79
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
10+
use Illuminate\Contracts\Cache\Repository as Cache;
811
use Illuminate\Support\Facades\Broadcast;
912
use Illuminate\Support\Facades\Bus;
1013
use Illuminate\Support\Facades\Queue;
@@ -33,6 +36,20 @@ public function testEventsCanBeBroadcast()
3336
Bus::assertNotDispatched(BroadcastEvent::class);
3437
Queue::assertPushed(BroadcastEvent::class);
3538
}
39+
40+
public function testUniqueEventsCanBeBroadcast()
41+
{
42+
Bus::fake();
43+
Queue::fake();
44+
45+
Broadcast::queue(new TestEventUnique);
46+
47+
Bus::assertNotDispatched(UniqueBroadcastEvent::class);
48+
Queue::assertPushed(UniqueBroadcastEvent::class);
49+
50+
$lockKey = 'laravel_unique_job:'.UniqueBroadcastEvent::class.TestEventUnique::class;
51+
$this->assertTrue($this->app->get(Cache::class)->lock($lockKey, 10)->get());
52+
}
3653
}
3754

3855
class TestEvent implements ShouldBroadcast
@@ -60,3 +77,16 @@ public function broadcastOn()
6077
//
6178
}
6279
}
80+
81+
class TestEventUnique implements ShouldBroadcast, ShouldBeUnique
82+
{
83+
/**
84+
* Get the channels the event should broadcast on.
85+
*
86+
* @return \Illuminate\Broadcasting\Channel|\Illuminate\Broadcasting\Channel[]
87+
*/
88+
public function broadcastOn()
89+
{
90+
//
91+
}
92+
}

0 commit comments

Comments
 (0)