Amazon SES Üzerinden Saniyede 100 E-posta Gönderebilen Bir E-posta Sırasını Nasıl Oluşturduk?


Yakında kullanıma sunmayı umduğumuz ve site e-postalarınızı Amazon SES üzerinden göndermeyi kolaylaştıracak yeni bir eklenti olan WP Offload SES'e bağlı kaldığım bir sır değil.

Daha önce bu blogda bahsetmiş olsam da bahsetmediğim bir şey, ondan beklediğiniz performanstır. Bu haftanın makalesinde, bir anlığına geri adım atmaya ve devreye soktuğumuz kuyruk sistemini ve ondan her son ons performansı nasıl sıyırmayı başardığımızı gözden geçirmeye karar verdim.

İşleri Planlamak

Yarasadan, bir e-posta kuyruğu uygulamamız gerektiğini biliyorduk, böylece e-postaları hemen göndermek yerine sıraya alınıp gruplar halinde işlendi. SMTP sunucuları genellikle yerleşik bir kuyruğa sahiptir, ancak SMTP yerine Amazon SES API'sini kullandığımız için kendi çözümümüzü sunmamız gerekiyor.

Kuyruk olmadan, sitenin bir kerede binlerce olmasa da yüzlerce e-posta göndermeye çalıştığı durumlarla karşılaşırdık ve bu, bellek veya isteği işlemek için zaman eksikliği nedeniyle kaçınılmaz olarak bir çökmeye yol açardı. Ayrıca, kesin olarak belirlenmemiş ve hesaptan hesaba değişen, dikkate alınması gereken Amazon SES oran sınırı da vardır.

Bir sıra oluşturmamız gerektiğini anladığımızda, aklım doğrudan kendi Ashley Rich'imiz tarafından oluşturulmuş bir WordPress eklentileri kütüphanesi olan WP Queue'ye gitti. Daha önce WP Migrate DB Pro Theme + Plugin Files eklentisi ve Image Processing Queue eklentisi gibi birkaç eklentide kullanmıştık.

Neden WP Sırası?

Bir işi kaydetmenize izin vermek ve daha sonra wp-cron aracılığıyla çalıştırılacak olan kuyruğa birden fazla iş eklemek için harika bir iş çıkarır.

Birkaç diğer kuyruk sistemine baktım ve hatta Amazon Simple Queue Service'e baktım. Ancak, güvenecek başka bir hizmete sahip olmanın ek fiyatı ve karmaşıklığı nedeniyle buna karşı karar verdim. Ayrıca, kuyruk sisteminde ince ayar veya değişiklik yapmamız gerekirse, bunu WP Queue ile yapmak Amazon SQS'den çok daha kolaydır.

AWS Komut Havuzu

İhtiyaçlarımız için WP Queue kullanmanın küçük bir dezavantajı, ilk gelen ilk hizmet esasına göre her seferinde bir işi tamamlamaya odaklanmasıdır. Bu basittir ve işe yarar, ancak günde binlerce e-posta göndermeyi amaçlayan kullanıcılar için yavaş olabilir.

Amazon SES'e yapılan ortalama API isteği yaklaşık 0,4 saniye sürebileceğinden, saniyede yalnızca birkaç e-posta göndermeyi bekleyebiliriz. Bunu aşmak için AWS, bir tane gönderip başka bir tane göndermeden önce yanıtı beklemek yerine, aynı anda birden çok e-posta göndermek için birden çok ileti dizisi kullanılmasını önerir.

Neyse ki Amazon, WP Boşaltma SES'in kullandığı PHP SDK'da bunu yapmanın bir yolunu geliştirdi. CommandPool nesnesi, API'ye gönderilecek ve bunları akıllıca gruplayacak bir dizi komutu manuel olarak eklemek için kullanılabilir.

Akışı Görselleştirme

Kuyruk sistemine karar verildiğinde, e-posta göndermek için eklentideki veri akışını görselleştirmek çok daha kolay:

WP Boşaltma SES e-posta kuyruğu şeması

uygulama

Şimdi eğlenceli kısım için – aslında sistemi uygulamak!

wp_mail()'i geçersiz kıl

İlk adım, takılabilir bir WordPress işlevi olan wp_mail() işlevini geçersiz kılmaktı. Bu, WordPress (ve uyumlu temalar ve eklentiler) aracılığıyla gönderilen tüm e-postaları dinlememize ve e-postayı hemen göndermek yerine kendi işlevselliğimizi kullanmamıza olanak tanır.

WP Boşaltma SES'te bu oldukça basittir – ana eklenti dosyasının altına aşağıdaki kodu eklememiz yeterlidir:

 if ( ! function_exists( 'wp_mail' ) ) { $settings = get_site_option( 'wposes_settings' ); if ( isset( $settings['send-via-ses'] ) && (bool) $settings['send-via-ses'] ) { function wp_mail( $to, $subject, $message, $headers = '', $attachments = array() ) { global $wp_offload_ses; $wp_offload_ses->mail_handler( $to, $subject, $message, $headers, $attachments ); } } }

Yukarıdakiler, wp_mail() işlevinin zaten geçersiz kılınmış olup olmadığını kontrol eder ve yapılmamışsa, WP Boşaltma SES eklentisi posta göndermek üzere yapılandırılmışsa kendi wp_mail() oluşturur.

Orijinal wp_mail() işleviyle aynı verileri kabul eder ve özel posta işleyicimize iletir.

Sıraya ekle

Ardından, e-postayı kuyruğa eklememiz gerekiyor. Yukarıdaki mail_hander() yöntemi, wp_mail() iletilen tüm öznitelikleri birleştirir ve kuyruğa yeni bir E-posta İşi wp_mail() :

 public function mail_handler( $to, $subject, $message, $headers, $attachments ) { $atts = apply_filters( 'wp_mail', compact( 'to', 'subject', 'message', 'headers', 'attachments' ) ); $settings = $this->settings->get_settings(); $this->get_queue()->push( new Email_Job( $atts, $settings ), $this->delay ); return true; }

Bu, e-posta işini daha sonra işlenmek üzere veritabanına kaydeder. E-posta işinden bahsetmişken, şuna benziyor:

 class Email_Job extends Job { /** * @var array */ private $atts; /** * @var array */ private $settings; /** * Pass any necessary data to the job. * * @param string $atts */ public function __construct( $atts, $settings ) { $this->atts = $atts; $this->settings = $settings; } /** * Handle the job logic. */ public function handle() { global $wp_offload_ses; if ( isset( $this->atts['to'] ) ) { $to = $this->atts['to']; } if ( isset( $this->atts['subject'] ) ) { $subject = $this->atts['subject']; } if ( isset( $this->atts['message'] ) ) { $message = $this->atts['message']; } if ( isset( $this->atts['headers'] ) ) { $headers = $this->atts['headers']; } if ( isset( $this->atts['attachments'] ) ) { $attachments = $this->atts['attachments']; } $client = $wp_offload_ses->get_ses_api()->get_client(); $email = new Email( $to, $subject, $message, $headers, $attachments, $this->settings ); $raw = $email->prepare(); $data = array( 'x-message-id' => $this->id(), 'RawMessage' => array( 'Data' => $raw, ), ); return $client->getCommand( 'SendRawEmail', $data ); } }

Kuyruk işleri işlerken, yapıcıda kendisine iletilen özniteliklerle birlikte Email_Job sınıfını veritabanından geri yükler ve ardından işi yürütmek için process() yöntemini çağırır.

Bu durumda, göndermeye hazır bir e-posta alır ve gerçekten göndermek için komutu döndürür – bu daha sonra CommandPool'da kullanılır.

CommandPool aracılığıyla gönder

Neyse ki AWS PHP SDK, daha fazla ince ayar yapmadan CommandPool'u kullanmaya başlamak için gereken sınıfları içerir. Üç ana yöntemi olan tüm ilgili mantığı işleyen bir sınıf oluşturdum. İlk olarak, havuza bir komut ekleyen add_command() işlevi vardır:

 public function add_command( $command ) { $this->commands[] = $command; $num_commands = count( $this->commands ); if ( $this->get_concurrency() === $num_commands || $this->connection->jobs() === $num_commands ) { $this->execute(); $this->commands = array(); } }

Ardından, bir komut sınırına ulaşıldığında, execute() işlevi çağrılır:

 private function execute() { global $wp_offload_ses; // Initiate the CommandPool $client = $wp_offload_ses->get_ses_api()->get_client(); $command_pool = new CommandPool( $client, $this->commands, [ 'concurrency' => $this->get_concurrency(), 'fulfilled' => function ( ResultInterface $result, $iterKey, PromiseInterface $aggregatePromise ) { $id = $this->commands[$iterKey]['x-message-id']; $job = $this->connection->get_job( $id ); $this->connection->delete( $job ); }, 'rejected' => function ( SesException $reason, $iterKey, PromiseInterface $aggregatePromise ) { $id = $this->commands[ $iterKey ]['x-message-id']; $job = $this->connection->get_job( $id ); $job->release(); if ( $job->attempts() >= $this->attempts ) { $job->fail(); } if ( $job->failed() ) { $this->connection->failure( $job, $reason ); } else { $this->connection->release( $job ); } } ]); // Send the emails in the pool $promise = $command_pool->promise(); $promise->wait(); }

Bu işlev, AWS CommandPool sınıfını başlatır ve istekleri eşzamansız olarak gönderir. Bununla ilgili güzel olan şey, API isteklerine verilen yanıtları işlemek için anonim işlevler de iletebilmenizdir, böylece tüm isteklerin gönderilmesini beklemek yerine her istek tamamlanır tamamlanmaz işlenir. Gerçekleştirilen anonim işlev, başarıyla fulfilled istekleri işler ve bunları kuyruktan siler; rejected işlev ise başarısız istekleri işler ve yeniden denenebilmesi için işi serbest bırakır. Bir istek belirli sayıdan fazla başarısız olursa (bu durumda 3) başarısız olarak işaretlenir ve otomatik olarak yeniden denenmez.

CommandPool eşzamanlılığının başka bir işlev tarafından ayarlandığını fark etmiş olabilirsiniz, get_concurrency() . Bu işlev, SES'ten maksimum gönderme hızını alır ve bunu CommandPool nesnesine ileterek Amazon SES hız sınırını aşmadan her zaman en yüksek kapasitede çalışmasını sağlar:

 private function get_concurrency() { global $wp_offload_ses; if ( ! is_null( $this->concurrency ) ) { return $this->concurrency; } $quota = $wp_offload_ses->get_ses_api()->get_send_quota(); $send_rate = 10; if ( ! is_wp_error( $quota ) ) { $send_rate = $quota['rate']; } $this->concurrency = (int) apply_filters( 'wposes_max_concurrency', $send_rate ); return $this->concurrency; }

Kuyruk, başka iş kalmayıncaya veya PHP zaman sınırına ulaşılıncaya kadar mevcut e-posta işleri üzerinde yinelenmeye devam edecektir. Bu gerçekleştiğinde, sıra sonraki wp_cron çalışmasına kadar durur ve ardından istekleri işlemeye devam eder.

kıyaslama

Tüm kodlar iliklendiğinde, her şeyin gerçekten işe yarayıp yaramadığını görmenin zamanı geldi. Uzak bir API'ye eşzamansız istekleri karşılaştırmak zor olduğu için, birkaç yüz e-postayı sıraya koyacak hızlı bir komut dosyasını bir araya getirdim ve her e-postanın gönderildiği zamanı günlüğe kaydetmek için CommandPool fulfilled işlevini değiştirdim.

WP Boşaltma SES kuyruğu performansı

Birkaç testten sonra, saniyede 100 e-postayı kolayca gönderdiği ortaya çıktı ve Amazon'un hız limitimi artırma konusundaki sürekli isteklerimi onaylaması durumunda daha da fazlasını göndereceğini tahmin ediyorum.

Yaşıyor!!

Son düşünceler

Bazıları için sıkıcı görünse de, olabildiğince çok e-posta göndermek için WP Boşaltma SES eklentisini optimize ederken çok eğlendim. Saniyede bir e-posta ile başlayıp, WP Kuyruğu ve AWS CommandPool'un eklenmesiyle bunu saniyede 100'e kadar e-postaya ulaştırmak çok tatmin ediciydi ve WP Boşaltma SES'in büyük miktarda e-postayı işlemede sorun yaşamayacağını garanti ediyor.

Daha önce hiç kuyruk sistemiyle çalıştınız mı? En iyi duruma getirdiğiniz ve şimdi gurur duyduğunuz herhangi bir kod var mı? Yorumlarda bize bildirin.

Copyright statement: Unless otherwise noted, this article is Collected from the Internet, please keep the source of the article when reprinting.

Check Also

Divi's Theme Builder ile Özel Global Başlık Nasıl Oluşturulur

Artık Tema Oluşturucu burada olduğuna göre, web sitenizi A'dan Z'ye kurmanıza yardımcı olacak yeni eğitimlere dalmak için sabırsızlanıyoruz. Buna Divi'nin yerleşik seçeneğini kullanarak özel başlıklar oluşturma da dahildir. Bu eğitimde Divi's Theme Builder'ı kullanarak global bir başlık oluşturmaya odaklanacağız. Bu sayfaya veya gönderiye farklı bir başlık atamadıysanız, web sitenizin her yerinde genel bir başlık görünecektir.

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir