Skip to content

Commit c560a67

Browse files
committed
Optimize garbage and serialize actions.
1 parent 77b8c60 commit c560a67

20 files changed

+599
-214
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
All notable changes to `laravel-mailator` will be documented in this file
44

5+
## 3.0.0 - 2021-06-08
6+
7+
- `actionClass` from MailatorScheduler now accept an instance of `Binarcode\LaravelMailator\Actions\Action`
8+
- `toDays()` helper added to MailatorScheduler
9+
- `tags()` added to MailatorScheduler
10+
511
## 2.0.0 - 2021-08-03
612

713
- The `before` and `after` methods now accept only an instance of Carbon

config/mailator.php

+5
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@
2626
> The email sender class. It will be executed from the sender job.
2727
*/
2828
'send_mail_action' => Binarcode\LaravelMailator\Actions\SendMailAction::class,
29+
30+
/**
31+
* Class that will mark the scheduled action as being completed so the action will do not be counted into the next iteration.
32+
*/
33+
'garbage_resolver' => Binarcode\LaravelMailator\Actions\ResolveGarbageAction::class,
2934
],
3035

3136
'log_model' => Binarcode\LaravelMailator\Models\MailatorLog::class,

database/migrations/create_mailator_tables.php.stub

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class CreateMailatorTables extends Migration
3131

3232
$table->timestamp('last_sent_at')->nullable();
3333
$table->timestamp('last_failed_at')->nullable();
34+
$table->timestamp('completed_at')->nullable();
3435
$table->text('failure_reason')->nullable();
3536
$table->timestamps();
3637
});

src/Actions/ResolveGarbageAction.php

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
namespace Binarcode\LaravelMailator\Actions;
4+
5+
use Binarcode\LaravelMailator\Models\MailatorSchedule;
6+
7+
class ResolveGarbageAction implements Action
8+
{
9+
public function handle(MailatorSchedule $schedule)
10+
{
11+
if ($this->shouldMarkComplete($schedule)) {
12+
$schedule->markComplete();
13+
}
14+
}
15+
16+
public function shouldMarkComplete(MailatorSchedule $schedule): bool
17+
{
18+
if ($schedule->isOnce() && $schedule->fresh()->last_sent_at) {
19+
return true;
20+
}
21+
22+
if ($schedule->isManual()) {
23+
return true;
24+
}
25+
26+
if ($schedule->isNever()) {
27+
return true;
28+
}
29+
30+
if ($schedule->isMany()) {
31+
return false;
32+
}
33+
34+
if (!$schedule->nextTrigger()) {
35+
return true;
36+
}
37+
38+
return false;
39+
}
40+
}

src/Actions/SendMailAction.php

+5
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,20 @@
44

55
use Binarcode\LaravelMailator\Events\ScheduleMailSentEvent;
66
use Binarcode\LaravelMailator\Models\MailatorSchedule;
7+
use Binarcode\LaravelMailator\Support\ClassResolver;
78
use Exception;
89
use Illuminate\Support\Facades\Mail;
910

1011
class SendMailAction implements Action
1112
{
13+
use ClassResolver;
14+
1215
public function handle(MailatorSchedule $schedule)
1316
{
1417
try {
1518
$this->sendMail($schedule);
19+
20+
static::garbageResolver()->handle($schedule);
1621
} catch (Exception $exception) {
1722
$schedule->markAsFailed($exception->getMessage());
1823

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
namespace Binarcode\LaravelMailator\Console\Commands;
4+
5+
use Binarcode\LaravelMailator\Models\MailatorSchedule;
6+
use Binarcode\LaravelMailator\Support\ClassResolver;
7+
use Illuminate\Console\Command;
8+
9+
class GarbageCollectorCommand extends Command
10+
{
11+
use ClassResolver;
12+
13+
protected $signature = 'mailator:garbage
14+
{--dry : Update items completed_at column}
15+
';
16+
17+
protected $description = 'Will mark as complete all executed mails.';
18+
19+
public function handle()
20+
{
21+
$this->info('----- Starting garbage cleaning -----');
22+
$ids = collect();
23+
24+
MailatorSchedule::query()
25+
->ready()
26+
->cursor()
27+
->each(function (MailatorSchedule $mailatorSchedule) use ($ids) {
28+
if ($this->option('dry')) {
29+
static::garbageResolver()->handle($mailatorSchedule);
30+
} elseif (static::garbageResolver()->shouldMarkComplete($mailatorSchedule)) {
31+
$ids->push($mailatorSchedule->id);
32+
}
33+
});
34+
35+
if (!$this->option('dry')) {
36+
$ids->each(fn($i) => $this->info('Scheduler id to complete: '.$i));
37+
}
38+
39+
$this->info("Marked as completed [".$ids->count()."] items.");
40+
$this->info('All done.');
41+
}
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
namespace Binarcode\LaravelMailator\Console\Commands;
4+
5+
use Binarcode\LaravelMailator\Models\MailatorSchedule;
6+
use Binarcode\LaravelMailator\Support\ClassResolver;
7+
use Illuminate\Console\Command;
8+
9+
class MailatorSchedulerCommand extends Command
10+
{
11+
use ClassResolver;
12+
13+
protected $signature = 'mailator:run';
14+
15+
protected $description = 'Run the mailator scheduler in Kernel.';
16+
17+
public function handle(): int
18+
{
19+
MailatorSchedule::run();
20+
21+
return 0;
22+
}
23+
}

src/Constraints/Descriptionable.php

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace Binarcode\LaravelMailator\Constraints;
4+
5+
interface Descriptionable
6+
{
7+
public static function conditions(): array;
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace Binarcode\LaravelMailator\Models\Builders;
4+
5+
use Illuminate\Database\Eloquent\Builder;
6+
7+
class MailatorSchedulerBuilder extends Builder
8+
{
9+
public function ready(): self
10+
{
11+
return $this->whereNull('completed_at');
12+
}
13+
}

src/Models/Concerns/ConstraintsResolver.php

+11
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Binarcode\LaravelMailator\Constraints\AfterConstraint;
77
use Binarcode\LaravelMailator\Constraints\BeforeConstraint;
88
use Binarcode\LaravelMailator\Constraints\DailyConstraint;
9+
use Binarcode\LaravelMailator\Constraints\Descriptionable;
910
use Binarcode\LaravelMailator\Constraints\ManualConstraint;
1011
use Binarcode\LaravelMailator\Constraints\ManyConstraint;
1112
use Binarcode\LaravelMailator\Constraints\NeverConstraint;
@@ -49,4 +50,14 @@ public function eventsPasses(): bool
4950
->filter(fn ($event) => is_subclass_of($event, SendScheduleConstraint::class))
5051
->every(fn (SendScheduleConstraint $event) => $event->canSend($this, $this->logs));
5152
}
53+
54+
public function constraintsDescriptions(): array
55+
{
56+
return collect($this->constraints)
57+
->map(fn(string $event) => unserialize($event))
58+
->filter(fn($event) => is_subclass_of($event, Descriptionable::class))
59+
->reduce(function ($base, Descriable $descriable) {
60+
return array_merge($base, $descriable::conditions());
61+
}, []);
62+
}
5263
}

src/Models/Concerns/HasFuture.php

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
namespace Binarcode\LaravelMailator\Models\Concerns;
4+
5+
6+
use Binarcode\LaravelMailator\Constraints\AfterConstraint;
7+
use Binarcode\LaravelMailator\Constraints\BeforeConstraint;
8+
use Binarcode\LaravelMailator\Constraints\Descriptionable;
9+
use Binarcode\LaravelMailator\Models\MailatorSchedule;
10+
use Carbon\CarbonInterface;
11+
12+
/**
13+
* Trait HasFuture
14+
* @mixin MailatorSchedule
15+
* @package Binarcode\LaravelMailator\Models\Concerns
16+
*/
17+
trait HasFuture
18+
{
19+
public function nextTrigger(): ?CarbonInterface
20+
{
21+
if (!$this->isFutureAction()) {
22+
return null;
23+
}
24+
25+
if ($this->isOnce() && $this->last_sent_at) {
26+
return null;
27+
}
28+
29+
return $this->timestamp_target->clone()->addDays(
30+
$this->toDays()
31+
);
32+
}
33+
34+
public function isFutureAction(): bool
35+
{
36+
if ($this->isManual()) {
37+
return false;
38+
}
39+
40+
if (is_null($this->timestamp_target)) {
41+
return false;
42+
}
43+
44+
if (is_null($this->time_frame_origin)) {
45+
return false;
46+
}
47+
48+
if ($this->time_frame_origin === static::TIME_FRAME_ORIGIN_AFTER) {
49+
return app(AfterConstraint::class)->canSend(
50+
$this,
51+
$this->logs
52+
);
53+
}
54+
55+
if ($this->time_frame_origin === static::TIME_FRAME_ORIGIN_BEFORE) {
56+
return app(BeforeConstraint::class)->canSend(
57+
$this,
58+
$this->logs
59+
);
60+
}
61+
62+
return false;
63+
}
64+
}

0 commit comments

Comments
 (0)