Skip to content

Commit

Permalink
[9.x] Add unique locking to broadcast events (#43416)
Browse files Browse the repository at this point in the history
* 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]>
  • Loading branch information
DougSisk and taylorotwell authored Jul 26, 2022
1 parent c73d856 commit d20d7ef
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 1 deletion.
6 changes: 5 additions & 1 deletion src/Illuminate/Broadcasting/BroadcastManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Illuminate\Broadcasting\Broadcasters\PusherBroadcaster;
use Illuminate\Broadcasting\Broadcasters\RedisBroadcaster;
use Illuminate\Contracts\Broadcasting\Factory as FactoryContract;
use Illuminate\Contracts\Broadcasting\ShouldBeUnique;
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
use Illuminate\Contracts\Bus\Dispatcher as BusDispatcherContract;
use Illuminate\Contracts\Foundation\CachesRoutes;
Expand Down Expand Up @@ -166,7 +167,10 @@ public function queue($event)
}

$this->app->make('queue')->connection($event->connection ?? null)->pushOn(
$queue, new BroadcastEvent(clone $event)
$queue,
$event instanceof ShouldBeUnique
? new UniqueBroadcastEvent(clone $event)
: new BroadcastEvent(clone $event)
);
}

Expand Down
60 changes: 60 additions & 0 deletions src/Illuminate/Broadcasting/UniqueBroadcastEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

namespace Illuminate\Broadcasting;

use Illuminate\Contracts\Queue\ShouldBeUnique;

class UniqueBroadcastEvent extends BroadcastEvent implements ShouldBeUnique
{
/**
* The unique lock identifier.
*
* @var mixed
*/
public $uniqueId;

/**
* The number of seconds the unique lock should be maintained.
*
* @var int
*/
public $uniqueFor;

/**
* The cache repository implementation that should be used to obtain unique locks.
*
* @var \Illuminate\Contracts\Cache\Repository
*/
public $uniqueVia;

/**
* Create a new job handler instance.
*
* @param mixed $event
* @return void
*/
public function __construct($event)
{
$this->uniqueId = get_class($event);

if (method_exists($event, 'uniqueId')) {
$this->uniqueId = $event->uniqueId();
} elseif (property_exists($event, 'uniqueId')) {
$this->uniqueId = $event->uniqueId;
}

if (method_exists($event, 'uniqueFor')) {
$this->uniqueFor = $event->uniqueFor();
} elseif (property_exists($event, 'uniqueFor')) {
$this->uniqueFor = $event->uniqueFor;
}

if (method_exists($event, 'uniqueVia')) {
$this->uniqueVia = $event->uniqueVia();
} elseif (property_exists($event, 'uniqueVia')) {
$this->uniqueVia = $event->uniqueVia;
}

parent::__construct($event);
}
}
8 changes: 8 additions & 0 deletions src/Illuminate/Contracts/Broadcasting/ShouldBeUnique.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Illuminate\Contracts\Broadcasting;

interface ShouldBeUnique
{
//
}
30 changes: 30 additions & 0 deletions tests/Integration/Broadcasting/BroadcastManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
namespace Illuminate\Tests\Integration\Broadcasting;

use Illuminate\Broadcasting\BroadcastEvent;
use Illuminate\Broadcasting\UniqueBroadcastEvent;
use Illuminate\Contracts\Broadcasting\ShouldBeUnique;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
use Illuminate\Contracts\Cache\Repository as Cache;
use Illuminate\Support\Facades\Broadcast;
use Illuminate\Support\Facades\Bus;
use Illuminate\Support\Facades\Queue;
Expand Down Expand Up @@ -33,6 +36,20 @@ public function testEventsCanBeBroadcast()
Bus::assertNotDispatched(BroadcastEvent::class);
Queue::assertPushed(BroadcastEvent::class);
}

public function testUniqueEventsCanBeBroadcast()
{
Bus::fake();
Queue::fake();

Broadcast::queue(new TestEventUnique);

Bus::assertNotDispatched(UniqueBroadcastEvent::class);
Queue::assertPushed(UniqueBroadcastEvent::class);

$lockKey = 'laravel_unique_job:'.UniqueBroadcastEvent::class.TestEventUnique::class;
$this->assertTrue($this->app->get(Cache::class)->lock($lockKey, 10)->get());
}
}

class TestEvent implements ShouldBroadcast
Expand Down Expand Up @@ -60,3 +77,16 @@ public function broadcastOn()
//
}
}

class TestEventUnique implements ShouldBroadcast, ShouldBeUnique
{
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|\Illuminate\Broadcasting\Channel[]
*/
public function broadcastOn()
{
//
}
}

0 comments on commit d20d7ef

Please sign in to comment.