-
Notifications
You must be signed in to change notification settings - Fork 11.2k
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
[5.1] Yet another attempt to fix Swift Mailer related SSL failures (Issue #4573) #13583
Conversation
@@ -392,7 +378,10 @@ protected function sendSwiftMessage($message) | |||
} | |||
|
|||
if (! $this->pretending) { | |||
return $this->swift->send($message, $this->failedRecipients); | |||
$result = $this->getSwiftMailer()->send($message, $this->failedRecipients); | |||
$this->getSwiftMailer()->getTransport()->stop(); |
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.
Please do a try finally here.
This will kill performance for someone sending lots of messages. |
@@ -392,7 +378,10 @@ protected function sendSwiftMessage($message) | |||
} | |||
|
|||
if (! $this->pretending) { | |||
return $this->swift->send($message, $this->failedRecipients); | |||
$result = $this->getSwiftMailer()->send($message, $this->failedRecipients); |
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.
please don't modify this line
The connection is stopped on each mail being sent, regardless of this change. The only difference here is the stop() being called after sending an email instead of calling it beforehand. I don't see any performance regressions here. |
- wrap try-finally around swift->send(); transport->stop();
Ok, so what is better: unreliable application (restarting the queue-workers via cronjob does not make an application more robust) - or faster delivery - which can be achieved running multiple queue-workers in parallel? The correct way would be to detect a faulty connection and then only reconnect then (which seems to be the current intend, but obviously not working). Will take a stable application that I can scale predictably any-time over some faulty hacked functionality. But that's just me :) |
try { | ||
return $this->swift->send($message, $this->failedRecipients); | ||
} finally { | ||
$this->getSwiftMailer()->getTransport()->stop(); |
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.
$this->swift->getTransport()->stop()
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.
Kind of inconsistent here anyway since Mailer::forceReconnection() uses the public getter, but I've changed it according to your comment.
Have y'all tested this with your own applications to verify it fixes the problem? |
@taylorotwell @lifeofguenter how about implementing my try-catch multiblocks? By the way, PRs are still here, may need some adjustment though: |
try { | ||
return $this->swift->send($message, $this->failedRecipients); | ||
} finally { | ||
$this->swift->getTransport()->stop(); |
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.
Why not just call "forceReconnection" here?
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.
@taylorotwell the problem is that stop()
may throw an exception, but even if it'll be catched - it won't reset transport. You need to call either reset()
, either stop() > start()
.
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.
Because calling "forceReconnection" would not make sense form a semantic point of view.
Guys, you're missing the point here. STOPping SMTP connection is slow and expensive operation, and shouldn't be done every time for every email to be sent. RESET is much faster and suits here better - however, in case of timeout it won't succeed. |
@YOzaz if you have a better solution then PR it. |
@YOzaz as said, what does it help if the fix is only suited for certain situations? Would still make email sending via SMTP super unreliable. If you need to send higher volumes, you still have the possibility to launch multiple queue-workers or outsource via services such as mandrill, that offer an async http API for sending bulk mails. |
@schanzel are you actually running this fix in production to verify that it works? |
@YOzaz What you are suggesting sounds a lot like premature optimisation and would add lots of unnecessary complexity. What you would normally want to do is open a connection, send a mail and finally close the connection. Handling any performance or network related problems should not be in focus here. Anything related to that should be handled by a dedicated connection pool, if needed (IMO). |
Can someone just answer the question as to whether this fix has actually been tested to solve the problem? 😆 |
@taylorotwell PR is here: #13609 |
@schanzel you're basically right, but - following this ideology SMTP connection in daemon workers should be handled same way like DB reconnection, as suggested here: https://laravel.com/docs/5.1/queues (see Coding Considerations For Daemon Queue Listeners). |
I should note that calling DB::reconnect is not needed in 5.2+…
|
@lifeofguenter sending emails through multiple queue tubes does not solve the problem in general - which is handling SMTP connections for long-running processes. |
@schanzel still need to know if this has been tested on a real app. |
Right, I'll leave PR as it is for now - Travis is failing because of change, therefore it needs more testing. |
Just deployed the fix at a larger scale to get somewhat more relibale information about whether or not this fix does the trick. The failures occure sporadically and are hard to reproduce. I'll get back to it once I got more information about it. |
Whats the status of this? We have this PR and @YOzaz's hanging out here and I'd like to get a solution merged in. |
We've had some internal problems which required a rollback, due to which this change was rollbacked also. I just deployed it again. I think I can give an answer by Wednesday or so. Please note that the rollback of the application was not related to this change ;-) |
Any updates on this? |
This looks good to me, seems to be the right solution and fix the issue. The only remaining change is remove method |
Since this fix is on production for a few days now, there are no SSL errors so far. I'd take this as an indication that the issue would be solved by this PR. |
@dbpolito Removing |
Gotcha. I'm going to need to push this fix to my prod manually too... Looking forward to get this merged and released into 5.2! 👍 |
This is my temp fix:
Which may also be another approach for fixing this. |
That can lead to terrible performance though. |
Define terrible performance? @GrahamCampbell |
If you turn off keeping the connection open, you have to negotiate everything. If negotiation takes 0.1 seconds, and sending an email takes 0.05, then sending 10 emails takes 3 times as long after this change. |
Can confirm it's now fixed, but emails do take a little longer to send. |
Thanks to @dbpolito , stopped the connection at the end of every Job that sends an email and everything seems fine now. Using Laravel 4.2. |
it solve my problem! thanks |
Closing swift mailer connection after sending the mail (see #4573 (comment))