From ccbb171312ccde082603781bb1d863b0169d3186 Mon Sep 17 00:00:00 2001 From: Patrick Landolt Date: Mon, 8 Apr 2019 17:57:55 +0200 Subject: [PATCH] fixed roundrobin dead transport which should recover --- .../Tests/Transport/FailoverTransportTest.php | 63 +++++++++++++++++++ .../Transport/RoundRobinTransportTest.php | 29 +++++++-- .../Mailer/Transport/RoundRobinTransport.php | 9 +++ 3 files changed, 96 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/Mailer/Tests/Transport/FailoverTransportTest.php b/src/Symfony/Component/Mailer/Tests/Transport/FailoverTransportTest.php index dc3bc21a7d..031dc32edb 100644 --- a/src/Symfony/Component/Mailer/Tests/Transport/FailoverTransportTest.php +++ b/src/Symfony/Component/Mailer/Tests/Transport/FailoverTransportTest.php @@ -64,6 +64,69 @@ class FailoverTransportTest extends TestCase $t->send(new RawMessage('')); } + public function testSendOneDeadAndRecoveryNotWithinRetryPeriod() + { + $t1 = $this->createMock(TransportInterface::class); + $t1->expects($this->at(0))->method('send')->will($this->throwException(new TransportException())); + $t1->expects($this->once())->method('send'); + $t2 = $this->createMock(TransportInterface::class); + $t2->expects($this->exactly(5))->method('send'); + $t = new FailoverTransport([$t1, $t2], 40); + $t->send(new RawMessage('')); + sleep(4); + $t->send(new RawMessage('')); + sleep(4); + $t->send(new RawMessage('')); + sleep(4); + $t->send(new RawMessage('')); + sleep(4); + $t->send(new RawMessage('')); + } + + public function testSendOneDeadAndRecoveryWithinRetryPeriod() + { + $t1 = $this->createMock(TransportInterface::class); + $t1->expects($this->at(0))->method('send')->will($this->throwException(new TransportException())); + $t1->expects($this->at(1))->method('send'); + $t1->expects($this->exactly(3))->method('send'); + $t2 = $this->createMock(TransportInterface::class); + $t2->expects($this->at(0))->method('send'); + $t2->expects($this->at(1))->method('send'); + $t2->expects($this->at(2))->method('send'); + $t2->expects($this->at(3))->method('send')->will($this->throwException(new TransportException())); + $t2->expects($this->exactly(4))->method('send'); + $t = new FailoverTransport([$t1, $t2], 6); + $t->send(new RawMessage('')); // t1>fail - t2>sent + sleep(4); + $t->send(new RawMessage('')); // t2>sent + sleep(4); + $t->send(new RawMessage('')); // t2>sent + sleep(4); + $t->send(new RawMessage('')); // t2>fail - t1>sent + sleep(4); + $t->send(new RawMessage('')); // t1>sent + } + + public function testSendAllDeadWithinRetryPeriod() + { + $t1 = $this->createMock(TransportInterface::class); + $t1->expects($this->at(0))->method('send')->will($this->throwException(new TransportException())); + $t1->expects($this->once())->method('send'); + $t2 = $this->createMock(TransportInterface::class); + $t2->expects($this->at(0))->method('send'); + $t2->expects($this->at(1))->method('send'); + $t2->expects($this->at(2))->method('send')->will($this->throwException(new TransportException())); + $t2->expects($this->exactly(3))->method('send'); + $t = new FailoverTransport([$t1, $t2], 40); + $t->send(new RawMessage('')); + sleep(4); + $t->send(new RawMessage('')); + sleep(4); + $this->expectException(TransportException::class); + $this->expectExceptionMessage('All transports failed.'); + $t->send(new RawMessage('')); + } + public function testSendOneDeadButRecover() { $t1 = $this->createMock(TransportInterface::class); diff --git a/src/Symfony/Component/Mailer/Tests/Transport/RoundRobinTransportTest.php b/src/Symfony/Component/Mailer/Tests/Transport/RoundRobinTransportTest.php index b27a3e7949..7acbe9c483 100644 --- a/src/Symfony/Component/Mailer/Tests/Transport/RoundRobinTransportTest.php +++ b/src/Symfony/Component/Mailer/Tests/Transport/RoundRobinTransportTest.php @@ -64,16 +64,35 @@ class RoundRobinTransportTest extends TestCase $t->send(new RawMessage('')); } - public function testSendOneDeadButRecover() + public function testSendOneDeadAndRecoveryNotWithinRetryPeriod() { $t1 = $this->createMock(TransportInterface::class); - $t1->expects($this->at(0))->method('send')->will($this->throwException(new TransportException())); - $t1->expects($this->at(1))->method('send'); + $t1->expects($this->exactly(4))->method('send'); $t2 = $this->createMock(TransportInterface::class); + $t2->expects($this->at(0))->method('send')->will($this->throwException(new TransportException())); $t2->expects($this->once())->method('send'); - $t = new RoundRobinTransport([$t1, $t2], 1); + $t = new RoundRobinTransport([$t1, $t2], 60); $t->send(new RawMessage('')); - sleep(2); + $t->send(new RawMessage('')); + $t->send(new RawMessage('')); + $t->send(new RawMessage('')); + } + + public function testSendOneDeadAndRecoveryWithinRetryPeriod() + { + $t1 = $this->createMock(TransportInterface::class); + $t1->expects($this->exactly(3))->method('send'); + $t2 = $this->createMock(TransportInterface::class); + $t2->expects($this->at(0))->method('send')->will($this->throwException(new TransportException())); + $t2->expects($this->at(1))->method('send'); + $t2->expects($this->exactly(2))->method('send'); + $t = new RoundRobinTransport([$t1, $t2], 3); + $t->send(new RawMessage('')); + sleep(5); + $t->send(new RawMessage('')); + sleep(5); + $t->send(new RawMessage('')); + sleep(5); $t->send(new RawMessage('')); } } diff --git a/src/Symfony/Component/Mailer/Transport/RoundRobinTransport.php b/src/Symfony/Component/Mailer/Transport/RoundRobinTransport.php index 22b1ba9714..e585e3635e 100644 --- a/src/Symfony/Component/Mailer/Transport/RoundRobinTransport.php +++ b/src/Symfony/Component/Mailer/Transport/RoundRobinTransport.php @@ -66,11 +66,20 @@ class RoundRobinTransport implements TransportInterface if (!$this->isTransportDead($transport)) { break; } + if ((microtime(true) - $this->deadTransports[$transport]) > $this->retryPeriod) { $this->deadTransports->detach($transport); break; } + + if ($transport) { + $this->transports[] = $transport; + } + + if ($this->deadTransports->count() >= \count($this->transports)) { + return null; + } } if ($transport) {