simple-java-mail
simple-java-mail copied to clipboard
Support primary/backup connection pool load balancing strategy
It will be very useful if there was support for primary/secondary (failover) strategy, so that a primary endpoint (say first one added) was used all the time, and only during failures would the subsequent endpoints be used.
.withConnectionPoolLoadBalancingStrategy(LoadBalancingStrategy.ROUND_ROBIN)
Otherwise, to achieve this I think we will need to instantiate multiple clients with different endpoints (not using the batch module) and then have a layer of try/catch. I would like to avoid this and let the library do the failover on failures only. Something like:
.withConnectionPoolLoadBalancingStrategy(LoadBalancingStrategy.FAILOVER)
If that is not something that can be added, could you help me identify if there is any other way I can achieve that without try/catch layer?
Thanks
That is an interesting thought. The problem though is that Simple Java Mail has no way of knowing the severity of any specific failure. It could be a whole range of reasons why something failed (or maybe even partially failed?).
So currently the support for failures is limited to try...catch so any user can implement his strategy for handling this. In your case those could be to try a second (again possibly clustered) mailer with a different endpoint as you say.
If you have more insight as to possible failures or standards for recognising retryable cases, I'm all ears though. 👍
What if just allow the user to call "send" with a primary/backup (or failover flag)? Basically they will get a failure, handle it, and decide wether to call the primary/backup. The library will handle all the connection pooling etc for all endpoints primary(s) and backup(s) endpoints, and the user will simply tell the library which one they want to use.
I agree with you though a user can simply just instantiate 2 Mailers, and use one or the other. The library supporting this is just a more out of the box experience, but since the try catch will still be handled by the user, its not as useful.
A user could also provide a failover policy of some sort (like a predicate), and the library would just delegate the failure handling upstream while still providing the failover support.
Yes, there are quite a few ways to approach this. Current workaround / canonical approach is to implement the exceptionHandler of a sent email:
// for async emails (sync emails simple try...catch)
mailer.sendMail(email)
.whenComplete((result, ex) -> { if (ex != null) sendUsingBackupMailer(email); });
Another approach could be to pass a failover handler, but the problem is determining the underlying cause (server issue vs issue with the email or connection setting on the client side). I would have to defer complete handling resulting not in a failover handler, but a generic exception handler. For this case I think the current implementation is the right abstraction level.
Another approach would be to auto retry n times with a new connection from the same pool each time, going to the same server.
Yet another approach would be an auto try another connection pool (cluster), guaranteeing a different Mailer instance and depending on the configuration guaranteeing a different server.
Of course these approaches could be layered too, performing graceful degradation of sorts.
Something to keep in mind here is that an exception does not automatically mean an email wasn't sent successfully. In theory an exception can occur after getting enough info to the server and depending on the server it could be an atomic or a partial success. Even if the session was a complete success, closing the connection could result in some exception for whatever reason. Automatically retrying in these cases is problematic obviously and I'm not aware of any ISO/RFC defaults of error codes marking these events.
This discussion has rested for some time now, I just reread everything.
It's clear Simple Java Mail cannot take responsibility for automatic retries or fail-over strategy, simply because there's nothing to base this decision on (and each server has its own exceptions). In fact it would be quite a feat if you manage to do this yourself, because if you just catch all exceptions, assume the mail wasn't sent and retry on a backup server, you might end up sending duplicate mails. Unless you have comprehensive exception analyses.
I would be very interested in any such comprehensive exception analyses (would be a great addition to the library), but I as don't believe it exists out there (and I did looked around a bit), I'm going to go ahead and close this feature request until I'm convinced otherwise. The example I gave is still the way to go, if you are ready to automate retries yourself -which I advice against, better to have a look at the log/exception first.