Skip to content

Commit bd6aa40

Browse files
authored
PHPORM-167 Fix and test MongoDB failed queue provider (#2838)
2 parents 5d6d2bd + 61368ef commit bd6aa40

File tree

3 files changed

+188
-4
lines changed

3 files changed

+188
-4
lines changed

Diff for: CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file.
55

66
* New aggregation pipeline builder by @GromNaN in [#2738](https://github.com/mongodb/laravel-mongodb/pull/2738)
77
* Drop support for Composer 1.x by @GromNaN in [#2784](https://github.com/mongodb/laravel-mongodb/pull/2784)
8+
* Fix `artisan query:retry` command by @GromNaN in [#2838](https://github.com/mongodb/laravel-mongodb/pull/2838)
89

910
## [4.2.0] - 2024-03-14
1011

Diff for: src/Queue/Failed/MongoFailedJobProvider.php

+37-4
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
namespace MongoDB\Laravel\Queue\Failed;
66

77
use Carbon\Carbon;
8+
use DateTimeInterface;
89
use Exception;
910
use Illuminate\Queue\Failed\DatabaseFailedJobProvider;
11+
use MongoDB\BSON\ObjectId;
1012
use MongoDB\BSON\UTCDateTime;
1113

1214
use function array_map;
@@ -55,16 +57,16 @@ public function all()
5557
/**
5658
* Get a single failed job.
5759
*
58-
* @param mixed $id
60+
* @param string $id
5961
*
60-
* @return object
62+
* @return object|null
6163
*/
6264
public function find($id)
6365
{
6466
$job = $this->getTable()->find($id);
6567

6668
if (! $job) {
67-
return;
69+
return null;
6870
}
6971

7072
$job['id'] = (string) $job['_id'];
@@ -75,12 +77,43 @@ public function find($id)
7577
/**
7678
* Delete a single failed job from storage.
7779
*
78-
* @param mixed $id
80+
* @param string $id
7981
*
8082
* @return bool
8183
*/
8284
public function forget($id)
8385
{
8486
return $this->getTable()->where('_id', $id)->delete() > 0;
8587
}
88+
89+
/**
90+
* Get the IDs of all the failed jobs.
91+
*
92+
* @param string|null $queue
93+
*
94+
* @return list<ObjectId>
95+
*/
96+
public function ids($queue = null)
97+
{
98+
return $this->getTable()
99+
->when($queue !== null, static fn ($query) => $query->where('queue', $queue))
100+
->orderBy('_id', 'desc')
101+
->pluck('_id')
102+
->all();
103+
}
104+
105+
/**
106+
* Prune all failed jobs older than the given date.
107+
*
108+
* @param DateTimeInterface $before
109+
*
110+
* @return int
111+
*/
112+
public function prune(DateTimeInterface $before)
113+
{
114+
return $this
115+
->getTable()
116+
->where('failed_at', '<', $before)
117+
->delete();
118+
}
86119
}

Diff for: tests/Queue/Failed/MongoFailedJobProviderTest.php

+150
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
<?php
2+
3+
namespace MongoDB\Laravel\Tests\Queue\Failed;
4+
5+
use Illuminate\Support\Facades\Date;
6+
use Illuminate\Support\Facades\DB;
7+
use MongoDB\BSON\ObjectId;
8+
use MongoDB\BSON\UTCDateTime;
9+
use MongoDB\Laravel\Queue\Failed\MongoFailedJobProvider;
10+
use MongoDB\Laravel\Tests\TestCase;
11+
use OutOfBoundsException;
12+
13+
use function array_map;
14+
use function range;
15+
use function sprintf;
16+
17+
class MongoFailedJobProviderTest extends TestCase
18+
{
19+
public function setUp(): void
20+
{
21+
parent::setUp();
22+
23+
DB::connection('mongodb')
24+
->collection('failed_jobs')
25+
->raw()
26+
->insertMany(array_map(static fn ($i) => [
27+
'_id' => new ObjectId(sprintf('%024d', $i)),
28+
'connection' => 'mongodb',
29+
'queue' => $i % 2 ? 'default' : 'other',
30+
'failed_at' => new UTCDateTime(Date::now()->subHours($i)),
31+
], range(1, 5)));
32+
}
33+
34+
public function tearDown(): void
35+
{
36+
DB::connection('mongodb')
37+
->collection('failed_jobs')
38+
->raw()
39+
->drop();
40+
41+
parent::tearDown();
42+
}
43+
44+
public function testLog(): void
45+
{
46+
$provider = $this->getProvider();
47+
48+
$provider->log('mongodb', 'default', '{"foo":"bar"}', new OutOfBoundsException('This is the error'));
49+
50+
$ids = $provider->ids();
51+
52+
$this->assertCount(6, $ids);
53+
54+
$inserted = $provider->find($ids[0]);
55+
56+
$this->assertSame('mongodb', $inserted->connection);
57+
$this->assertSame('default', $inserted->queue);
58+
$this->assertSame('{"foo":"bar"}', $inserted->payload);
59+
$this->assertStringContainsString('OutOfBoundsException: This is the error', $inserted->exception);
60+
$this->assertInstanceOf(ObjectId::class, $inserted->_id);
61+
$this->assertSame((string) $inserted->_id, $inserted->id);
62+
}
63+
64+
public function testCount(): void
65+
{
66+
$provider = $this->getProvider();
67+
68+
$this->assertEquals(5, $provider->count());
69+
$this->assertEquals(3, $provider->count('mongodb', 'default'));
70+
$this->assertEquals(2, $provider->count('mongodb', 'other'));
71+
}
72+
73+
public function testAll(): void
74+
{
75+
$all = $this->getProvider()->all();
76+
77+
$this->assertCount(5, $all);
78+
$this->assertEquals(new ObjectId(sprintf('%024d', 5)), $all[0]->_id);
79+
$this->assertEquals(sprintf('%024d', 5), $all[0]->id, 'id field is added for compatibility with DatabaseFailedJobProvider');
80+
}
81+
82+
public function testFindAndForget(): void
83+
{
84+
$provider = $this->getProvider();
85+
86+
$id = sprintf('%024d', 2);
87+
$found = $provider->find($id);
88+
89+
$this->assertIsObject($found, 'The job is found');
90+
$this->assertEquals(new ObjectId($id), $found->_id);
91+
$this->assertObjectHasProperty('failed_at', $found);
92+
93+
// Delete the job
94+
$result = $provider->forget($id);
95+
96+
$this->assertTrue($result, 'forget return true when the job have been deleted');
97+
$this->assertNull($provider->find($id), 'the job have been deleted');
98+
99+
// Delete the same job again
100+
$result = $provider->forget($id);
101+
102+
$this->assertFalse($result, 'forget return false when the job does not exist');
103+
104+
$this->assertCount(4, $provider->ids(), 'Other jobs are kept');
105+
}
106+
107+
public function testIds(): void
108+
{
109+
$ids = $this->getProvider()->ids();
110+
111+
$this->assertCount(5, $ids);
112+
$this->assertEquals(new ObjectId(sprintf('%024d', 5)), $ids[0]);
113+
}
114+
115+
public function testIdsFilteredByQuery(): void
116+
{
117+
$ids = $this->getProvider()->ids('other');
118+
119+
$this->assertCount(2, $ids);
120+
$this->assertEquals(new ObjectId(sprintf('%024d', 4)), $ids[0]);
121+
}
122+
123+
public function testFlush(): void
124+
{
125+
$provider = $this->getProvider();
126+
127+
$this->assertEquals(5, $provider->count());
128+
129+
$provider->flush(4);
130+
131+
$this->assertEquals(3, $provider->count());
132+
}
133+
134+
public function testPrune(): void
135+
{
136+
$provider = $this->getProvider();
137+
138+
$this->assertEquals(5, $provider->count());
139+
140+
$result = $provider->prune(Date::now()->subHours(4));
141+
142+
$this->assertEquals(2, $result);
143+
$this->assertEquals(3, $provider->count());
144+
}
145+
146+
private function getProvider(): MongoFailedJobProvider
147+
{
148+
return new MongoFailedJobProvider(DB::getFacadeRoot(), '', 'failed_jobs');
149+
}
150+
}

0 commit comments

Comments
 (0)