Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[9.x] Release lock for job implementing ShouldBeUnique that is dispatched afterResponse() #46806

Merged
merged 9 commits into from
Apr 18, 2023
2 changes: 1 addition & 1 deletion src/Illuminate/Bus/Dispatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ protected function pushCommandToQueue($queue, $command)
public function dispatchAfterResponse($command, $handler = null)
{
$this->container->terminating(function () use ($command, $handler) {
$this->dispatchNow($command, $handler);
$this->dispatchSync($command, $handler);
});
}

Expand Down
2 changes: 1 addition & 1 deletion src/Illuminate/Foundation/Bus/Dispatchable.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public static function dispatchNow(...$arguments)
*/
public static function dispatchAfterResponse(...$arguments)
{
return app(Dispatcher::class)->dispatchAfterResponse(new static(...$arguments));
return self::dispatch(...$arguments)->afterResponse();
}

/**
Expand Down
59 changes: 59 additions & 0 deletions tests/Integration/Queue/JobDispatchingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
namespace Illuminate\Tests\Integration\Queue;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Cache\Repository;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Orchestra\Testbench\TestCase;

class JobDispatchingTest extends TestCase
Expand Down Expand Up @@ -70,6 +73,52 @@ public function testDoesNotDispatchConditionallyWithClosure()

$this->assertTrue(Job::$ran);
}

public function testUniqueJobLockIsReleasedForJobDispatchedAfterResponse()
{
// get initial terminatingCallbacks
$terminatingCallbacksReflectionProperty = (new \ReflectionObject($this->app))->getProperty('terminatingCallbacks');
$terminatingCallbacksReflectionProperty->setAccessible(true);
$startTerminatingCallbacks = $terminatingCallbacksReflectionProperty->getValue($this->app);

UniqueJob::dispatchAfterResponse('test');
$this->assertFalse(
$this->getJobLock(UniqueJob::class, 'test')
);

$this->app->terminate();
$this->assertTrue(UniqueJob::$ran);

$terminatingCallbacksReflectionProperty->setValue($this->app, $startTerminatingCallbacks);

UniqueJob::$ran = false;
UniqueJob::dispatch('test')->afterResponse();
$this->app->terminate();
$this->assertTrue(UniqueJob::$ran);

// acquire job lock and confirm that job is not dispatched after response
$this->assertTrue(
$this->getJobLock(UniqueJob::class, 'test')
);
$terminatingCallbacksReflectionProperty->setValue($this->app, $startTerminatingCallbacks);
UniqueJob::$ran = false;
UniqueJob::dispatch('test')->afterResponse();
$this->app->terminate();
$this->assertFalse(UniqueJob::$ran);

// confirm that dispatchAfterResponse also does not run
UniqueJob::dispatchAfterResponse('test');
$this->app->terminate();
$this->assertFalse(UniqueJob::$ran);
}

/**
* Helpers.
*/
private function getJobLock($job, $value = null)
{
return $this->app->get(Repository::class)->lock('laravel_unique_job:'.$job.$value, 10)->get();
}
}

class Job implements ShouldQueue
Expand All @@ -96,3 +145,13 @@ public function replaceValue($value)
static::$value = $value;
}
}

class UniqueJob extends Job implements ShouldBeUnique
{
use InteractsWithQueue;

public function uniqueId()
{
return self::$value;
}
}