I have two services for sending emails, Postmark and SendGrid. I used Factory Pattern to be expandable and flexible.
EmailProviderInterface
namespace App\Services\Notifications;
interface EmailProviderInterface
{
public function sendEmail(string $to, string $templateName, array $data);
}
PostMarkEmailService
<?php
namespace App\Services\Notifications;
use App\Traits\SendEmailTrait;
class PostmarkEmailService implements EmailProviderInterface
{
use SendEmailTrait;
/**
* send email using postmark
*
* @param string $to
* @param string $templateName
* @param array $data
* @return array
*/
public function sendEmail(string $to, string $templateName, array $data): array
{
$templateInfo = $this->getHtmlRender($templateName, $data);
if (!$templateInfo['success']) {
return $templateInfo;
}
try {
// implement logic calling external api and passing the html
return $this->successHandler();
} catch (\Exception $e) {
return $this->handleErrors($e);
}
}
}
SendGridEmailService
<?php
namespace App\Services\Notifications;
use App\Traits\SendEmailTrait;
class SendGridEmailService implements EmailProviderInterface
{
use SendEmailTrait;
/**
* Send Email Using SendGrid
*
* @param string $to
* @param string $templateName
* @param array $data
* @return array
*/
public function sendEmail(string $to, string $templateName, array $data): array
{
$templateInfo = $this->getHtmlRender($templateName, $data);
if (!$templateInfo['success']) {
return $templateInfo;
}
try {
// implement logic calling external api and passing the html
return $this->successHandler();
} catch (\Exception $e) {
return $this->handleErrors($e);
}
}
}
and this is EmailServiceProvider that will use it:
<?php
namespace App\Services\Notifications;
class EmailServiceProvider
{
private EmailProviderInterface $emailProvider;
public function __construct(bool $highPriority = true)
{
if ($highPriority) {
$this->emailProvider = new PostmarkEmailService();
} else {
$this->emailProvider = new SendGridEmailService();
}
}
/**
* Send email using the email provider
*
* @param string $to
* @param string $templateName
* @param array $data
* @return array
*/
public function sendMail(string $to, string $templateName, array $data): array
{
return $this->emailProvider->sendEmail($to, $templateName, $data);
}
}
I need to implement a load balancer (using a round robin strategy) with a retry mechanism. This would operate on the EmailService provider to swap between PostMark And SendGrid services.
If I were to implement a queue, how can apply such a load balancer?
To implement Load Balacing with retries in your EmailServiceProvider, you can update
constructorandsendMailmethod.You can also implement load balancing at the queue level by leveraging a message broker such as
RabbitMQorRedis.These message brokers support load balancing mechanisms out of the box, allowing you distribute the processing of email jobs across multiple worker processes or machines.