Skip to content

Commit

Permalink
[10.x] Allow failed jobs to be counted by "connection" and "queue" (#…
Browse files Browse the repository at this point in the history
…48216)

* Allow failed jobs to be counted by "connection" and "queue"

* Fix and improve tests

* additional tests

* lint

* standardise
  • Loading branch information
timacdonald authored Aug 29, 2023
1 parent 0ccc2d9 commit d8a7bd9
Show file tree
Hide file tree
Showing 8 changed files with 276 additions and 34 deletions.
15 changes: 15 additions & 0 deletions src/Illuminate/Queue/Failed/CountableFailedJobProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace Illuminate\Queue\Failed;

interface CountableFailedJobProvider
{
/**
* Count the failed jobs.
*
* @param string|null $connection
* @param string|null $queue
* @return int
*/
public function count($connection = null, $queue = null);
}
14 changes: 10 additions & 4 deletions src/Illuminate/Queue/Failed/DatabaseFailedJobProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@

namespace Illuminate\Queue\Failed;

use Countable;
use DateTimeInterface;
use Illuminate\Database\ConnectionResolverInterface;
use Illuminate\Support\Facades\Date;

class DatabaseFailedJobProvider implements Countable, FailedJobProviderInterface, PrunableFailedJobProvider
class DatabaseFailedJobProvider implements CountableFailedJobProvider, FailedJobProviderInterface, PrunableFailedJobProvider
{
/**
* The connection resolver implementation.
Expand Down Expand Up @@ -133,10 +132,17 @@ public function prune(DateTimeInterface $before)

/**
* Count the failed jobs.
*
* @param string|null $connection
* @param string|null $queue
* @return int
*/
public function count(): int
public function count($connection = null, $queue = null)
{
return $this->getTable()->count();
return $this->getTable()
->when($connection, fn ($builder) => $builder->whereConnection($connection))
->when($queue, fn ($builder) => $builder->whereQueue($queue))
->count();
}

/**
Expand Down
14 changes: 10 additions & 4 deletions src/Illuminate/Queue/Failed/DatabaseUuidFailedJobProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@

namespace Illuminate\Queue\Failed;

use Countable;
use DateTimeInterface;
use Illuminate\Database\ConnectionResolverInterface;
use Illuminate\Support\Facades\Date;

class DatabaseUuidFailedJobProvider implements Countable, FailedJobProviderInterface, PrunableFailedJobProvider
class DatabaseUuidFailedJobProvider implements CountableFailedJobProvider, FailedJobProviderInterface, PrunableFailedJobProvider
{
/**
* The connection resolver implementation.
Expand Down Expand Up @@ -146,10 +145,17 @@ public function prune(DateTimeInterface $before)

/**
* Count the failed jobs.
*
* @param string|null $connection
* @param string|null $queue
* @return int
*/
public function count(): int
public function count($connection = null, $queue = null)
{
return $this->getTable()->count();
return $this->getTable()
->when($connection, fn ($builder) => $builder->whereConnection($connection))
->when($queue, fn ($builder) => $builder->whereQueue($queue))
->count();
}

/**
Expand Down
17 changes: 13 additions & 4 deletions src/Illuminate/Queue/Failed/FileFailedJobProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
namespace Illuminate\Queue\Failed;

use Closure;
use Countable;
use DateTimeInterface;
use Illuminate\Support\Facades\Date;

class FileFailedJobProvider implements Countable, FailedJobProviderInterface, PrunableFailedJobProvider
class FileFailedJobProvider implements CountableFailedJobProvider, FailedJobProviderInterface, PrunableFailedJobProvider
{
/**
* The file path where the failed job file should be stored.
Expand Down Expand Up @@ -206,9 +205,19 @@ protected function write(array $jobs)

/**
* Count the failed jobs.
*
* @param string|null $connection
* @param string|null $queue
* @return int
*/
public function count(): int
public function count($connection = null, $queue = null)
{
return count($this->read());
if (($connection ?? $queue) === null) {
return count($this->read());
}

return collect($this->read())
->filter(fn ($job) => $job->connection === ($connection ?? $job->connection) && $job->queue === ($queue ?? $job->queue))
->count();
}
}
10 changes: 6 additions & 4 deletions src/Illuminate/Queue/Failed/NullFailedJobProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

namespace Illuminate\Queue\Failed;

use Countable;

class NullFailedJobProvider implements Countable, FailedJobProviderInterface
class NullFailedJobProvider implements CountableFailedJobProvider, FailedJobProviderInterface
{
/**
* Log a failed job into storage.
Expand Down Expand Up @@ -65,8 +63,12 @@ public function flush($hours = null)

/**
* Count the failed jobs.
*
* @param string|null $connection
* @param string|null $queue
* @return int
*/
public function count(): int
public function count($connection = null, $queue = null)
{
return 0;
}
Expand Down
91 changes: 87 additions & 4 deletions tests/Queue/DatabaseFailedJobProviderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,96 @@ public function testJobsCanBeCounted()
});
$provider = new DatabaseFailedJobProvider($db->getDatabaseManager(), 'default', 'failed_jobs');

$this->assertCount(0, $provider);
$this->assertSame(0, $provider->count());

$provider->log('database', 'default', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$this->assertCount(1, $provider);
$this->assertSame(1, $provider->count());

$provider->log('database', 'default', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$provider->log('database', 'default', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$this->assertCount(3, $provider);
$provider->log('another-connection', 'another-queue', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$this->assertSame(3, $provider->count());
}

public function testJobsCanBeCountedByConnection()
{
$db = new DB;
$db->addConnection([
'driver' => 'sqlite',
'database' => ':memory:',
]);
$db->getConnection()->getSchemaBuilder()->create('failed_jobs', function (Blueprint $table) {
$table->id();
$table->text('connection');
$table->text('queue');
$table->longText('payload');
$table->longText('exception');
$table->timestamp('failed_at')->useCurrent();
});
$provider = new DatabaseFailedJobProvider($db->getDatabaseManager(), 'default', 'failed_jobs');

$provider->log('connection-1', 'default', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$provider->log('connection-2', 'default', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$this->assertSame(1, $provider->count('connection-1'));
$this->assertSame(1, $provider->count('connection-2'));

$provider->log('connection-1', 'default', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$this->assertSame(2, $provider->count('connection-1'));
$this->assertSame(1, $provider->count('connection-2'));
}

public function testJobsCanBeCountedByQueue()
{
$db = new DB;
$db->addConnection([
'driver' => 'sqlite',
'database' => ':memory:',
]);
$db->getConnection()->getSchemaBuilder()->create('failed_jobs', function (Blueprint $table) {
$table->id();
$table->text('connection');
$table->text('queue');
$table->longText('payload');
$table->longText('exception');
$table->timestamp('failed_at')->useCurrent();
});
$provider = new DatabaseFailedJobProvider($db->getDatabaseManager(), 'default', 'failed_jobs');

$provider->log('database', 'queue-1', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$provider->log('database', 'queue-2', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$this->assertSame(1, $provider->count(queue: 'queue-1'));
$this->assertSame(1, $provider->count(queue: 'queue-2'));

$provider->log('database', 'queue-1', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$this->assertSame(2, $provider->count(queue: 'queue-1'));
$this->assertSame(1, $provider->count(queue: 'queue-2'));
}

public function testJobsCanBeCountedByQueueAndConnection()
{
$db = new DB;
$db->addConnection([
'driver' => 'sqlite',
'database' => ':memory:',
]);
$db->getConnection()->getSchemaBuilder()->create('failed_jobs', function (Blueprint $table) {
$table->id();
$table->text('connection');
$table->text('queue');
$table->longText('payload');
$table->longText('exception');
$table->timestamp('failed_at')->useCurrent();
});
$provider = new DatabaseFailedJobProvider($db->getDatabaseManager(), 'default', 'failed_jobs');

$provider->log('connection-1', 'queue-99', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$provider->log('connection-1', 'queue-99', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$provider->log('connection-2', 'queue-99', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$provider->log('connection-1', 'queue-1', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$provider->log('connection-2', 'queue-1', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$provider->log('connection-2', 'queue-1', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$this->assertSame(2, $provider->count('connection-1', 'queue-99'));
$this->assertSame(1, $provider->count('connection-2', 'queue-99'));
$this->assertSame(1, $provider->count('connection-1', 'queue-1'));
$this->assertSame(2, $provider->count('connection-2', 'queue-1'));
}
}
95 changes: 89 additions & 6 deletions tests/Queue/DatabaseUuidFailedJobProviderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,96 @@ public function testJobsCanBeCounted()
});
$provider = new DatabaseUuidFailedJobProvider($db->getDatabaseManager(), 'default', 'failed_jobs');

$this->assertCount(0, $provider);
$this->assertSame(0, $provider->count());

$provider->log('database', 'default', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$this->assertCount(1, $provider);
$provider->log('connection-1', 'queue-1', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$this->assertSame(1, $provider->count());

$provider->log('database', 'default', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$provider->log('database', 'default', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$this->assertCount(3, $provider);
$provider->log('connection-1', 'queue-1', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$provider->log('connection-2', 'queue-2', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$this->assertSame(3, $provider->count());
}

public function testJobsCanBeCountedByConnection()
{
$db = new DB;
$db->addConnection([
'driver' => 'sqlite',
'database' => ':memory:',
]);
$db->getConnection()->getSchemaBuilder()->create('failed_jobs', function (Blueprint $table) {
$table->uuid();
$table->text('connection');
$table->text('queue');
$table->longText('payload');
$table->longText('exception');
$table->timestamp('failed_at')->useCurrent();
});
$provider = new DatabaseUuidFailedJobProvider($db->getDatabaseManager(), 'default', 'failed_jobs');

$provider->log('connection-1', 'default', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$provider->log('connection-2', 'default', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$this->assertSame(1, $provider->count('connection-1'));
$this->assertSame(1, $provider->count('connection-2'));

$provider->log('connection-1', 'default', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$this->assertSame(2, $provider->count('connection-1'));
$this->assertSame(1, $provider->count('connection-2'));
}

public function testJobsCanBeCountedByQueue()
{
$db = new DB;
$db->addConnection([
'driver' => 'sqlite',
'database' => ':memory:',
]);
$db->getConnection()->getSchemaBuilder()->create('failed_jobs', function (Blueprint $table) {
$table->uuid();
$table->text('connection');
$table->text('queue');
$table->longText('payload');
$table->longText('exception');
$table->timestamp('failed_at')->useCurrent();
});
$provider = new DatabaseUuidFailedJobProvider($db->getDatabaseManager(), 'default', 'failed_jobs');

$provider->log('database', 'queue-1', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$provider->log('database', 'queue-2', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$this->assertSame(1, $provider->count(queue: 'queue-1'));
$this->assertSame(1, $provider->count(queue: 'queue-2'));

$provider->log('database', 'queue-1', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$this->assertSame(2, $provider->count(queue: 'queue-1'));
$this->assertSame(1, $provider->count(queue: 'queue-2'));
}

public function testJobsCanBeCountedByQueueAndConnection()
{
$db = new DB;
$db->addConnection([
'driver' => 'sqlite',
'database' => ':memory:',
]);
$db->getConnection()->getSchemaBuilder()->create('failed_jobs', function (Blueprint $table) {
$table->uuid();
$table->text('connection');
$table->text('queue');
$table->longText('payload');
$table->longText('exception');
$table->timestamp('failed_at')->useCurrent();
});
$provider = new DatabaseUuidFailedJobProvider($db->getDatabaseManager(), 'default', 'failed_jobs');

$provider->log('connection-1', 'queue-99', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$provider->log('connection-1', 'queue-99', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$provider->log('connection-2', 'queue-99', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$provider->log('connection-1', 'queue-1', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$provider->log('connection-2', 'queue-1', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$provider->log('connection-2', 'queue-1', json_encode(['uuid' => (string) Str::uuid()]), new RuntimeException());
$this->assertSame(2, $provider->count('connection-1', 'queue-99'));
$this->assertSame(1, $provider->count('connection-2', 'queue-99'));
$this->assertSame(1, $provider->count('connection-1', 'queue-1'));
$this->assertSame(2, $provider->count('connection-2', 'queue-1'));
}
}
Loading

0 comments on commit d8a7bd9

Please sign in to comment.