Skip to content

Commit a8363e4

Browse files
[11.x] Fix integrity constraint violation on failed_jobs_uuid_unique (#53264)
* [11.x] Fix integrity constraint violation on failed_jobs_uuid_unique (#53230) * notify observer * remove old code * style ci * add test * style ci * skip test on redis/beanstalkd * Revert "style ci" This reverts commit ff22f3a. * Revert "remove old code" This reverts commit 2086b6c. * Revert "[11.x] Fix integrity constraint violation on failed_jobs_uuid_unique (#53230)" This reverts commit 51a0eba * use static var * reset static vars * formatting --------- Co-authored-by: Taylor Otwell <[email protected]>
1 parent 57af5c3 commit a8363e4

File tree

3 files changed

+62
-0
lines changed

3 files changed

+62
-0
lines changed

src/Illuminate/Foundation/Testing/Concerns/InteractsWithTestCaseLifecycle.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use Illuminate\Foundation\Testing\WithoutMiddleware;
2222
use Illuminate\Http\Middleware\TrustHosts;
2323
use Illuminate\Http\Middleware\TrustProxies;
24+
use Illuminate\Queue\Console\WorkCommand;
2425
use Illuminate\Queue\Queue;
2526
use Illuminate\Support\Carbon;
2627
use Illuminate\Support\Facades\Facade;
@@ -178,6 +179,7 @@ protected function tearDownTheTestEnvironment(): void
178179
TrustProxies::flushState();
179180
TrustHosts::flushState();
180181
ValidateCsrfToken::flushState();
182+
WorkCommand::flushState();
181183

182184
if ($this->callbackException) {
183185
throw $this->callbackException;

src/Illuminate/Queue/Console/WorkCommand.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@ class WorkCommand extends Command
7676
*/
7777
protected $latestStartedAt;
7878

79+
/**
80+
* Indicates if the worker's event listeners have been registered.
81+
*
82+
* @var bool
83+
*/
84+
private static $hasRegisteredListeners = false;
85+
7986
/**
8087
* Create a new queue work command.
8188
*
@@ -172,6 +179,10 @@ protected function gatherWorkerOptions()
172179
*/
173180
protected function listenForEvents()
174181
{
182+
if (static::$hasRegisteredListeners) {
183+
return;
184+
}
185+
175186
$this->laravel['events']->listen(JobProcessing::class, function ($event) {
176187
$this->writeOutput($event->job, 'starting');
177188
});
@@ -189,6 +200,8 @@ protected function listenForEvents()
189200

190201
$this->logFailedJob($event);
191202
});
203+
204+
static::$hasRegisteredListeners = true;
192205
}
193206

194207
/**
@@ -360,4 +373,14 @@ protected function outputUsingJson()
360373

361374
return $this->option('json');
362375
}
376+
377+
/**
378+
* Reset static variables.
379+
*
380+
* @return void
381+
*/
382+
public static function flushState()
383+
{
384+
static::$hasRegisteredListeners = false;
385+
}
363386
}

tests/Integration/Queue/WorkCommandTest.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,16 @@
44

55
use Illuminate\Bus\Queueable;
66
use Illuminate\Contracts\Queue\ShouldQueue;
7+
use Illuminate\Database\UniqueConstraintViolationException;
78
use Illuminate\Foundation\Bus\Dispatchable;
89
use Illuminate\Foundation\Testing\DatabaseMigrations;
10+
use Illuminate\Queue\Console\WorkCommand;
911
use Illuminate\Support\Carbon;
12+
use Illuminate\Support\Facades\Artisan;
13+
use Illuminate\Support\Facades\Exceptions;
1014
use Illuminate\Support\Facades\Queue;
1115
use Orchestra\Testbench\Attributes\WithMigration;
16+
use RuntimeException;
1217

1318
#[WithMigration]
1419
#[WithMigration('queue')]
@@ -29,6 +34,13 @@ protected function setUp(): void
2934
$this->markTestSkippedWhenUsingSyncQueueDriver();
3035
}
3136

37+
protected function tearDown(): void
38+
{
39+
WorkCommand::flushState();
40+
41+
parent::tearDown();
42+
}
43+
3244
public function testRunningOneJob()
3345
{
3446
Queue::push(new FirstJob);
@@ -157,6 +169,21 @@ public function testMaxTimeExceeded()
157169
$this->assertFalse(FirstJob::$ran);
158170
$this->assertFalse(SecondJob::$ran);
159171
}
172+
173+
public function testFailedJobListenerOnlyRunsOnce()
174+
{
175+
$this->markTestSkippedWhenUsingQueueDrivers(['redis', 'beanstalkd']);
176+
177+
Exceptions::fake();
178+
179+
Queue::push(new FirstJob);
180+
$this->withoutMockingConsoleOutput()->artisan('queue:work', ['--once' => true, '--sleep' => 0]);
181+
182+
Queue::push(new JobWillFail);
183+
$this->withoutMockingConsoleOutput()->artisan('queue:work', ['--once' => true]);
184+
Exceptions::assertNotReported(UniqueConstraintViolationException::class);
185+
$this->assertSame(2, substr_count(Artisan::output(), JobWillFail::class));
186+
}
160187
}
161188

162189
class FirstJob implements ShouldQueue
@@ -196,3 +223,13 @@ public function handle()
196223
static::$ran = true;
197224
}
198225
}
226+
227+
class JobWillFail implements ShouldQueue
228+
{
229+
use Dispatchable, Queueable;
230+
231+
public function handle()
232+
{
233+
throw new RuntimeException;
234+
}
235+
}

0 commit comments

Comments
 (0)