-
-
Notifications
You must be signed in to change notification settings - Fork 73
add FallbackMailer #28
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,132 @@ | ||
| <?php | ||
|
|
||
| /** | ||
| * This file is part of the Nette Framework (https://nette.org) | ||
| * Copyright (c) 2004 David Grudl (https://davidgrudl.com) | ||
| */ | ||
|
|
||
| namespace Nette\Mail; | ||
|
|
||
| use Nette; | ||
| use Nette\InvalidArgumentException; | ||
|
|
||
|
|
||
| class FallbackMailer implements IMailer | ||
| { | ||
| use Nette\SmartObject; | ||
|
|
||
| /** @var callable[] function (FallbackMailer $sender, SendException $e, IMailer $mailer, Message $mail) */ | ||
| public $onFailure; | ||
|
|
||
| /** @var IMailer[] */ | ||
| private $mailers; | ||
|
|
||
| /** @var int */ | ||
| private $retryCount; | ||
|
|
||
| /** @var int in miliseconds */ | ||
| private $retryWaitTime; | ||
|
|
||
|
|
||
| /** | ||
| * @param IMailer[] | ||
| * @param int | ||
| * @param int in miliseconds | ||
| */ | ||
| public function __construct(array $mailers, $retryCount = 3, $retryWaitTime = 1000) | ||
| { | ||
| if (!$mailers) { | ||
| throw new InvalidArgumentException('At least one mailer must be provided.'); | ||
| } | ||
|
|
||
| $this->mailers = $mailers; | ||
| $this->retryCount = $retryCount; | ||
| $this->retryWaitTime = $retryWaitTime; | ||
| } | ||
|
|
||
|
|
||
| /** | ||
| * Sends email. | ||
| * @return void | ||
| * @throws FallbackMailerException | ||
| */ | ||
| public function send(Message $mail) | ||
| { | ||
| for ($i = 0; $i < $this->retryCount; $i++) { | ||
| if ($i > 0) { | ||
| usleep($this->retryWaitTime * 1000); | ||
| } | ||
|
|
||
| foreach ($this->mailers as $mailer) { | ||
| try { | ||
| $mailer->send($mail); | ||
| return; | ||
|
|
||
| } catch (SendException $e) { | ||
| $failures[] = $e; | ||
| $this->onFailure($this, $e, $mailer, $mail); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| $e = new FallbackMailerException('All mailers failed to send the message.', 0, $failures[0]); | ||
| $e->failures = $failures; | ||
| throw $e; | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. self note: wrap this with another SendException instance |
||
| } | ||
|
|
||
|
|
||
| /** | ||
| * @return IMailer[] | ||
| */ | ||
| public function getMailers() | ||
| { | ||
| return $this->mailers; | ||
| } | ||
|
|
||
|
|
||
| /** | ||
| * @param IMailer[] | ||
| * @return self | ||
| */ | ||
| public function addMailer(IMailer $mailer) | ||
| { | ||
| $this->mailers[] = $mailer; | ||
| } | ||
|
|
||
|
|
||
| /** | ||
| * @return int | ||
| */ | ||
| public function getRetryCount() | ||
| { | ||
| return $this->retryCount; | ||
| } | ||
|
|
||
|
|
||
| /** | ||
| * @param int | ||
| */ | ||
| public function setRetryCount($retryCount) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All setters in nette should return |
||
| { | ||
| $this->retryCount = $retryCount; | ||
| } | ||
|
|
||
|
|
||
| /** | ||
| * @return int in miliseconds | ||
| */ | ||
| public function getRetryWaitTime() | ||
| { | ||
| return $this->retryWaitTime; | ||
| } | ||
|
|
||
|
|
||
| /** | ||
| * @param int in miliseconds | ||
| */ | ||
| public function setRetryWaitTime($retryWaitTime) | ||
| { | ||
| $this->retryWaitTime = $retryWaitTime; | ||
| } | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| <?php | ||
|
|
||
| /** | ||
| * Test: Nette\Mail\FallbackMailer | ||
| */ | ||
|
|
||
| use Nette\Mail\FallbackMailer; | ||
| use Nette\Mail\FallbackMailerException; | ||
| use Nette\Mail\IMailer; | ||
| use Nette\Mail\Message; | ||
| use Nette\Mail\SendException; | ||
| use Tester\Assert; | ||
|
|
||
|
|
||
| require __DIR__ . '/../bootstrap.php'; | ||
|
|
||
| require __DIR__ . '/Mail.php'; | ||
|
|
||
|
|
||
| class FailingMailer implements IMailer | ||
| { | ||
| private $failedTimes; | ||
|
|
||
|
|
||
| public function __construct($failedTimes) | ||
| { | ||
| $this->failedTimes = $failedTimes; | ||
| } | ||
|
|
||
|
|
||
| public function send(Message $mail) | ||
| { | ||
| static $count = 0; | ||
| if ($this->failedTimes--) { | ||
| throw new SendException('Failure #' . (++$count)); | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
||
| $send = function () { | ||
| $message = new Message(); | ||
| $this->send($message); | ||
| }; | ||
|
|
||
|
|
||
| test(function () use ($send) { | ||
| $subMailerA = new FailingMailer(3); | ||
| $subMailerB = new FailingMailer(3); | ||
|
|
||
| $mailer = new FallbackMailer([$subMailerA, $subMailerB], 3, 10); | ||
| $mailer->onFailure[] = function (FallbackMailer $sender, SendException $e, IMailer $mailer, Message $mail) use (& $onFailureCalls) { | ||
| $onFailureCalls[] = $mailer; | ||
| }; | ||
|
|
||
| $e = Assert::exception($send->bindTo($mailer), FallbackMailerException::class, 'All mailers failed to send the message.'); | ||
| Assert::same([$subMailerA, $subMailerB, $subMailerA, $subMailerB, $subMailerA, $subMailerB], $onFailureCalls); | ||
| Assert::count(6, $e->failures); | ||
| Assert::same('Failure #1', $e->getPrevious()->getMessage()); | ||
| }); | ||
|
|
||
|
|
||
| test(function () use ($send) { | ||
| $subMailerA = new FailingMailer(3); | ||
| $subMailerB = new FailingMailer(2); | ||
|
|
||
| $mailer = new FallbackMailer([$subMailerA, $subMailerB], 3, 10); | ||
| $mailer->onFailure[] = function (FallbackMailer $sender, SendException $e, IMailer $mailer, Message $mail) use (& $onFailureCalls) { | ||
| $onFailureCalls[] = $mailer; | ||
| }; | ||
|
|
||
| $send->bindTo($mailer)->__invoke(); | ||
| Assert::same([$subMailerA, $subMailerB, $subMailerA, $subMailerB, $subMailerA], $onFailureCalls); | ||
| }); | ||
|
|
||
|
|
||
| test(function () use ($send) { | ||
| $subMailerA = new FailingMailer(0); | ||
| $subMailerB = new FailingMailer(2); | ||
|
|
||
| $mailer = new FallbackMailer([$subMailerA, $subMailerB], 3, 10); | ||
| $mailer->onFailure[] = function (FallbackMailer $sender, SendException $e, IMailer $mailer, Message $mail) use (& $onFailureCalls) { | ||
| $onFailureCalls[] = $mailer; | ||
| }; | ||
|
|
||
| $send->bindTo($mailer)->__invoke(); | ||
| Assert::null($onFailureCalls); | ||
| }); |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about to check, that mailers is not empty?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, I'll add the check in constructor.