Sending queue refactoring WIP [MAILPOET-903]
This commit is contained in:
@ -2,6 +2,7 @@
|
||||
namespace MailPoet\Models;
|
||||
use Carbon\Carbon;
|
||||
use MailPoet\Newsletter\Renderer\Renderer;
|
||||
use MailPoet\Tasks\Sending as SendingTask;
|
||||
use MailPoet\Util\Helpers;
|
||||
use MailPoet\Util\Security;
|
||||
use MailPoet\WP\Emoji;
|
||||
@ -107,12 +108,24 @@ class Newsletter extends Model {
|
||||
'SET `deleted_at` = NOW() ' .
|
||||
'WHERE `parent_id` = ' . $this->id
|
||||
);
|
||||
ScheduledTask::rawExecute(
|
||||
'UPDATE `' . ScheduledTask::$_table . '` t ' .
|
||||
'JOIN `' . SendingQueue::$_table . '` q ON t.`id` = q.`task_id` ' .
|
||||
'SET t.`deleted_at` = NOW() ' .
|
||||
'WHERE q.`newsletter_id` IN (' . join(',', array_merge(Helpers::flattenArray($children), array($this->id))) . ')'
|
||||
);
|
||||
SendingQueue::rawExecute(
|
||||
'UPDATE `' . SendingQueue::$_table . '` ' .
|
||||
'SET `deleted_at` = NOW() ' .
|
||||
'WHERE `newsletter_id` IN (' . join(',', array_merge(Helpers::flattenArray($children), array($this->id))) . ')'
|
||||
);
|
||||
} else {
|
||||
ScheduledTask::rawExecute(
|
||||
'UPDATE `' . ScheduledTask::$_table . '` t ' .
|
||||
'JOIN `' . SendingQueue::$_table . '` q ON t.`id` = q.`task_id` ' .
|
||||
'SET t.`deleted_at` = NOW() ' .
|
||||
'WHERE q.`newsletter_id` = ' . $this->id
|
||||
);
|
||||
SendingQueue::rawExecute(
|
||||
'UPDATE `' . SendingQueue::$_table . '` ' .
|
||||
'SET `deleted_at` = NOW() ' .
|
||||
@ -133,12 +146,24 @@ class Newsletter extends Model {
|
||||
'SET `deleted_at` = NOW() ' .
|
||||
'WHERE `parent_id` IN (' . join(',', Helpers::flattenArray($ids)) . ')'
|
||||
);
|
||||
ScheduledTask::rawExecute(
|
||||
'UPDATE `' . ScheduledTask::$_table . '` t ' .
|
||||
'JOIN `' . SendingQueue::$_table . '` q ON t.`id` = q.`task_id` ' .
|
||||
'SET t.`deleted_at` = NOW() ' .
|
||||
'WHERE q.`newsletter_id` IN (' . join(',', array_merge(Helpers::flattenArray($children), $ids)) . ')'
|
||||
);
|
||||
SendingQueue::rawExecute(
|
||||
'UPDATE `' . SendingQueue::$_table . '` ' .
|
||||
'SET `deleted_at` = NOW() ' .
|
||||
'WHERE `newsletter_id` IN (' . join(',', array_merge(Helpers::flattenArray($children), $ids)) . ')'
|
||||
);
|
||||
} else {
|
||||
ScheduledTask::rawExecute(
|
||||
'UPDATE `' . ScheduledTask::$_table . '` t ' .
|
||||
'JOIN `' . SendingQueue::$_table . '` q ON t.`id` = q.`task_id` ' .
|
||||
'SET t.`deleted_at` = NOW() ' .
|
||||
'WHERE q.`newsletter_id` IN (' . join(',', Helpers::flattenArray($ids)) . ')'
|
||||
);
|
||||
SendingQueue::rawExecute(
|
||||
'UPDATE `' . SendingQueue::$_table . '` ' .
|
||||
'SET `deleted_at` = NOW() ' .
|
||||
@ -156,9 +181,11 @@ class Newsletter extends Model {
|
||||
if($children) {
|
||||
$children = Helpers::flattenArray($children);
|
||||
$this->children()->deleteMany();
|
||||
SendingQueue::getTasks()->whereIn('queues.newsletter_id', array_merge($children, array($this->id)))->deleteMany();
|
||||
SendingQueue::whereIn('newsletter_id', array_merge($children, array($this->id)))->deleteMany();
|
||||
NewsletterSegment::whereIn('newsletter_id', array_merge($children, array($this->id)))->deleteMany();
|
||||
} else {
|
||||
SendingQueue::getTasks()->where('queues.newsletter_id', $this->id)->deleteMany();
|
||||
$this->queue()->deleteMany();
|
||||
$this->segmentRelations()->deleteMany();
|
||||
}
|
||||
@ -173,9 +200,11 @@ class Newsletter extends Model {
|
||||
if($children) {
|
||||
$children = Helpers::flattenArray($children);
|
||||
Newsletter::whereIn('parent_id', $ids)->deleteMany();
|
||||
SendingQueue::getTasks()->whereIn('queues.newsletter_id', array_merge($children, $ids))->deleteMany();
|
||||
SendingQueue::whereIn('newsletter_id', array_merge($children, $ids))->deleteMany();
|
||||
NewsletterSegment::whereIn('newsletter_id', array_merge($children, $ids))->deleteMany();
|
||||
} else {
|
||||
SendingQueue::getTasks()->whereIn('queues.newsletter_id', $ids)->deleteMany();
|
||||
SendingQueue::whereIn('newsletter_id', $ids)->deleteMany();
|
||||
NewsletterSegment::whereIn('newsletter_id', $ids)->deleteMany();
|
||||
}
|
||||
@ -193,12 +222,24 @@ class Newsletter extends Model {
|
||||
'SET `deleted_at` = null ' .
|
||||
'WHERE `parent_id` = ' . $this->id
|
||||
);
|
||||
ScheduledTask::rawExecute(
|
||||
'UPDATE `' . ScheduledTask::$_table . '` t ' .
|
||||
'JOIN `' . SendingQueue::$_table . '` q ON t.`id` = q.`task_id` ' .
|
||||
'SET t.`deleted_at` = null ' .
|
||||
'WHERE q.`newsletter_id` IN (' . join(',', array_merge(Helpers::flattenArray($children), array($this->id))) . ')'
|
||||
);
|
||||
SendingQueue::rawExecute(
|
||||
'UPDATE `' . SendingQueue::$_table . '` ' .
|
||||
'SET `deleted_at` = null ' .
|
||||
'WHERE `newsletter_id` IN (' . join(',', array_merge(Helpers::flattenArray($children), array($this->id))) . ')'
|
||||
);
|
||||
} else {
|
||||
ScheduledTask::rawExecute(
|
||||
'UPDATE `' . ScheduledTask::$_table . '` t ' .
|
||||
'JOIN `' . SendingQueue::$_table . '` q ON t.`id` = q.`task_id` ' .
|
||||
'SET t.`deleted_at` = null ' .
|
||||
'WHERE q.`newsletter_id` = ' . $this->id
|
||||
);
|
||||
SendingQueue::rawExecute(
|
||||
'UPDATE `' . SendingQueue::$_table . '` ' .
|
||||
'SET `deleted_at` = null ' .
|
||||
@ -223,12 +264,24 @@ class Newsletter extends Model {
|
||||
->findResultSet()
|
||||
->set('deleted_at', null)
|
||||
->save();
|
||||
SendingQueue::getTasks()
|
||||
->whereIn('queues.newsletter_id', Helpers::flattenArray($children))
|
||||
->whereNotNull('deleted_at')
|
||||
->findResultSet()
|
||||
->set('deleted_at', null)
|
||||
->save();
|
||||
SendingQueue::whereIn('newsletter_id', Helpers::flattenArray($children))
|
||||
->whereNotNull('deleted_at')
|
||||
->findResultSet()
|
||||
->set('deleted_at', null)
|
||||
->save();
|
||||
} else {
|
||||
SendingQueue::getTasks()
|
||||
->whereIn('queues.newsletter_id', $ids)
|
||||
->whereNotNull('deleted_at')
|
||||
->findResultSet()
|
||||
->set('deleted_at', null)
|
||||
->save();
|
||||
SendingQueue::whereIn('newsletter_id', $ids)
|
||||
->whereNotNull('deleted_at')
|
||||
->findResultSet()
|
||||
@ -408,23 +461,11 @@ class Newsletter extends Model {
|
||||
}
|
||||
|
||||
function getQueue($columns = '*') {
|
||||
return SendingQueue::select($columns)
|
||||
->where('newsletter_id', $this->id)
|
||||
->orderByDesc('updated_at')
|
||||
->findOne();
|
||||
return SendingTask::getByNewsletterId($this->id);
|
||||
}
|
||||
|
||||
function withSendingQueue() {
|
||||
$queue = $this->getQueue(array(
|
||||
'id',
|
||||
'newsletter_id',
|
||||
'newsletter_rendered_subject',
|
||||
'status',
|
||||
'count_processed',
|
||||
'count_total',
|
||||
'scheduled_at',
|
||||
'created_at'
|
||||
));
|
||||
$queue = $this->getQueue();
|
||||
if($queue === false) {
|
||||
$this->queue = false;
|
||||
} else {
|
||||
@ -445,9 +486,9 @@ class Newsletter extends Model {
|
||||
|
||||
function withTotalSent() {
|
||||
// total of subscribers who received the email
|
||||
$this->total_sent = (int)SendingQueue::where('newsletter_id', $this->id)
|
||||
->where('status', SendingQueue::STATUS_COMPLETED)
|
||||
->sum('count_processed');
|
||||
$this->total_sent = (int)SendingQueue::findTaskByNewsletterId($this->id)
|
||||
->where('tasks.status', SendingQueue::STATUS_COMPLETED)
|
||||
->sum('queues.count_processed');
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -480,8 +521,9 @@ class Newsletter extends Model {
|
||||
} else {
|
||||
$row = $statisticsExpr
|
||||
->join(MP_SENDING_QUEUES_TABLE, array("queue_id", "=", "qt.id"), "qt")
|
||||
->join(MP_SCHEDULED_TASKS_TABLE, array("qt.task_Id", "=", "tasks.id"), "tasks")
|
||||
->where(array(
|
||||
"qt.status" => SendingQueue::STATUS_COMPLETED,
|
||||
"tasks.status" => SendingQueue::STATUS_COMPLETED,
|
||||
"stat.newsletter_id" => $this->id,
|
||||
))->findOne();
|
||||
}
|
||||
@ -511,8 +553,13 @@ class Newsletter extends Model {
|
||||
'queues.newsletter_id = newsletters.id',
|
||||
'queues'
|
||||
)
|
||||
->where('queues.status', SendingQueue::STATUS_COMPLETED)
|
||||
->whereGte('queues.processed_at', Carbon::now()->subMonths(3))
|
||||
->join(
|
||||
MP_SCHEDULED_TASKS_TABLE,
|
||||
'queues.task_id = tasks.id',
|
||||
'tasks'
|
||||
)
|
||||
->where('tasks.status', SendingQueue::STATUS_COMPLETED)
|
||||
->whereGte('tasks.processed_at', Carbon::now()->subMonths(3))
|
||||
->count();
|
||||
|
||||
|
||||
@ -862,10 +909,15 @@ class Newsletter extends Model {
|
||||
'queues.newsletter_id = newsletters.id',
|
||||
'queues'
|
||||
)
|
||||
->where('queues.status', SendingQueue::STATUS_COMPLETED)
|
||||
->join(
|
||||
MP_SCHEDULED_TASKS_TABLE,
|
||||
'queues.task_id = tasks.id',
|
||||
'tasks'
|
||||
)
|
||||
->where('tasks.status', SendingQueue::STATUS_COMPLETED)
|
||||
->whereNull('newsletters.deleted_at')
|
||||
->select('queues.processed_at')
|
||||
->orderByDesc('queues.processed_at');
|
||||
->select('tasks.processed_at')
|
||||
->orderByDesc('tasks.processed_at');
|
||||
|
||||
if(!empty($segment_ids)) {
|
||||
$orm->join(
|
||||
|
@ -7,10 +7,32 @@ class ScheduledTask extends Model {
|
||||
public static $_table = MP_SCHEDULED_TASKS_TABLE;
|
||||
const STATUS_COMPLETED = 'completed';
|
||||
const STATUS_SCHEDULED = 'scheduled';
|
||||
const STATUS_PAUSED = 'paused';
|
||||
const PRIORITY_HIGH = 1;
|
||||
const PRIORITY_MEDIUM = 5;
|
||||
const PRIORITY_LOW = 10;
|
||||
|
||||
function subscribers() {
|
||||
return $this->hasManyThrough(
|
||||
__NAMESPACE__.'\Subscriber',
|
||||
__NAMESPACE__.'\ScheduledTaskSubscriber',
|
||||
'task_id',
|
||||
'subscriber_id'
|
||||
);
|
||||
}
|
||||
|
||||
function pause() {
|
||||
$this->set('status', self::STATUS_PAUSED);
|
||||
$this->save();
|
||||
return ($this->getErrors() === false && $this->id() > 0);
|
||||
}
|
||||
|
||||
function resume() {
|
||||
$this->setExpr('status', 'NULL');
|
||||
$this->save();
|
||||
return ($this->getErrors() === false && $this->id() > 0);
|
||||
}
|
||||
|
||||
function complete() {
|
||||
$this->processed_at = current_time('mysql');
|
||||
$this->set('status', self::STATUS_COMPLETED);
|
||||
|
@ -10,6 +10,10 @@ class ScheduledTaskSubscriber extends Model {
|
||||
public static $_table = MP_SCHEDULED_TASK_SUBSCRIBERS_TABLE;
|
||||
public static $_id_column = array('task_id', 'subscriber_id');
|
||||
|
||||
function task() {
|
||||
return $this->hasOne(__NAMESPACE__ . '\ScheduledTask', 'id', 'task_id');
|
||||
}
|
||||
|
||||
static function createOrUpdate($data = array()) {
|
||||
if(!is_array($data) || empty($data['task_id']) || empty($data['subscriber_id'])) {
|
||||
return;
|
||||
@ -21,6 +25,11 @@ class ScheduledTaskSubscriber extends Model {
|
||||
));
|
||||
}
|
||||
|
||||
static function setSubscribers($task_id, array $subscriber_ids) {
|
||||
static::clearSubscribers($task_id);
|
||||
return static::addSubscribers($task_id, $subscriber_ids);
|
||||
}
|
||||
|
||||
static function addSubscribers($task_id, array $subscriber_ids) {
|
||||
foreach($subscriber_ids as $subscriber_id) {
|
||||
self::createOrUpdate(array(
|
||||
@ -30,6 +39,10 @@ class ScheduledTaskSubscriber extends Model {
|
||||
}
|
||||
}
|
||||
|
||||
static function clearSubscribers($task_id) {
|
||||
return self::where('task_id', $task_id)->deleteMany();
|
||||
}
|
||||
|
||||
static function getUnprocessedCount($task_id) {
|
||||
return self::getCount($task_id, self::STATUS_UNPROCESSED);
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ namespace MailPoet\Models;
|
||||
|
||||
use MailPoet\Util\Helpers;
|
||||
use MailPoet\WP\Emoji;
|
||||
use MailPoet\Tasks\Subscribers as TaskSubscribers;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
@ -23,6 +24,10 @@ class SendingQueue extends Model {
|
||||
));
|
||||
}
|
||||
|
||||
function task() {
|
||||
return $this->hasOne(__NAMESPACE__ . '\ScheduledTask', 'id', 'task_id');
|
||||
}
|
||||
|
||||
function newsletter() {
|
||||
return $this->has_one(__NAMESPACE__ . '\Newsletter', 'id', 'newsletter_id');
|
||||
}
|
||||
@ -31,9 +36,7 @@ class SendingQueue extends Model {
|
||||
if($this->count_processed === $this->count_total) {
|
||||
return false;
|
||||
} else {
|
||||
$this->set('status', self::STATUS_PAUSED);
|
||||
$this->save();
|
||||
return ($this->getErrors() === false && $this->id() > 0);
|
||||
return $this->task()->findOne()->pause();
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,23 +44,16 @@ class SendingQueue extends Model {
|
||||
if($this->count_processed === $this->count_total) {
|
||||
return $this->complete();
|
||||
} else {
|
||||
$this->setExpr('status', 'NULL');
|
||||
$this->save();
|
||||
return ($this->getErrors() === false && $this->id() > 0);
|
||||
return $this->task()->findOne()->resume();
|
||||
}
|
||||
}
|
||||
|
||||
function complete() {
|
||||
$this->set('status', self::STATUS_COMPLETED);
|
||||
$this->save();
|
||||
return ($this->getErrors() === false && $this->id() > 0);
|
||||
return $this->task()->findOne()->complete();
|
||||
}
|
||||
|
||||
function save() {
|
||||
$this->newsletter_rendered_body = $this->getNewsletterRenderedBody();
|
||||
if(!is_serialized($this->subscribers) && !is_null($this->subscribers)) {
|
||||
$this->set('subscribers', serialize($this->subscribers));
|
||||
}
|
||||
if(!Helpers::isJson($this->newsletter_rendered_body) && !is_null($this->newsletter_rendered_body)) {
|
||||
$this->set(
|
||||
'newsletter_rendered_body',
|
||||
@ -69,22 +65,10 @@ class SendingQueue extends Model {
|
||||
$this->priority = self::PRIORITY_MEDIUM;
|
||||
}
|
||||
parent::save();
|
||||
$this->subscribers = $this->getSubscribers();
|
||||
$this->newsletter_rendered_body = $this->getNewsletterRenderedBody();
|
||||
return $this;
|
||||
}
|
||||
|
||||
function getSubscribers() {
|
||||
if(!is_serialized($this->subscribers)) {
|
||||
return $this->subscribers;
|
||||
}
|
||||
$subscribers = unserialize($this->subscribers);
|
||||
if(empty($subscribers['processed'])) {
|
||||
$subscribers['processed'] = array();
|
||||
}
|
||||
return $subscribers;
|
||||
}
|
||||
|
||||
function getNewsletterRenderedBody($type = false) {
|
||||
$rendered_newsletter = $this->decodeRenderedNewsletterBodyObject($this->newsletter_rendered_body);
|
||||
return ($type && !empty($rendered_newsletter[$type])) ?
|
||||
@ -115,57 +99,16 @@ class SendingQueue extends Model {
|
||||
}
|
||||
|
||||
function isSubscriberProcessed($subscriber_id) {
|
||||
$subscribers = $this->getSubscribers();
|
||||
return in_array($subscriber_id, $subscribers['processed']);
|
||||
return (new TaskSubscribers($this->task()->findOne()))
|
||||
->isSubscriberProcessed($subscriber_id);
|
||||
}
|
||||
|
||||
function asArray() {
|
||||
$model = parent::asArray();
|
||||
$model['subscribers'] = $this->getSubscribers();
|
||||
$model['newsletter_rendered_body'] = $this->getNewsletterRenderedBody();
|
||||
return $model;
|
||||
}
|
||||
|
||||
function removeSubscribers($subscribers_to_remove) {
|
||||
$subscribers = $this->getSubscribers();
|
||||
$subscribers['to_process'] = array_values(
|
||||
array_diff(
|
||||
$subscribers['to_process'],
|
||||
$subscribers_to_remove
|
||||
)
|
||||
);
|
||||
$this->subscribers = $subscribers;
|
||||
$this->updateCount();
|
||||
}
|
||||
|
||||
function updateProcessedSubscribers($processed_subscribers) {
|
||||
$subscribers = $this->getSubscribers();
|
||||
$subscribers['processed'] = array_merge(
|
||||
$subscribers['processed'],
|
||||
$processed_subscribers
|
||||
);
|
||||
$subscribers['to_process'] = array_values(
|
||||
array_diff(
|
||||
$subscribers['to_process'],
|
||||
$processed_subscribers
|
||||
)
|
||||
);
|
||||
$this->subscribers = $subscribers;
|
||||
return $this->updateCount()->getErrors() === false;
|
||||
}
|
||||
|
||||
function updateCount() {
|
||||
$this->subscribers = $this->getSubscribers();
|
||||
$this->count_processed = count($this->subscribers['processed']);
|
||||
$this->count_to_process = count($this->subscribers['to_process']);
|
||||
$this->count_total = $this->count_processed + $this->count_to_process;
|
||||
if(!$this->count_to_process) {
|
||||
$this->processed_at = current_time('mysql');
|
||||
$this->status = self::STATUS_COMPLETED;
|
||||
}
|
||||
return $this->save();
|
||||
}
|
||||
|
||||
private function decodeRenderedNewsletterBodyObject($rendered_body) {
|
||||
if(is_serialized($rendered_body)) {
|
||||
return $this->decodeEmojisInBody(unserialize($rendered_body));
|
||||
@ -175,4 +118,36 @@ class SendingQueue extends Model {
|
||||
}
|
||||
return $rendered_body;
|
||||
}
|
||||
}
|
||||
|
||||
static function getTasks() {
|
||||
return ScheduledTask::table_alias('tasks')
|
||||
->join(
|
||||
MP_SENDING_QUEUES_TABLE,
|
||||
'tasks.id = queues.task_id',
|
||||
'queues'
|
||||
);
|
||||
}
|
||||
|
||||
static function joinWithTasks() {
|
||||
return static::table_alias('queues')
|
||||
->join(
|
||||
MP_SCHEDULED_TASKS_TABLE,
|
||||
'tasks.id = queues.task_id',
|
||||
'tasks'
|
||||
);
|
||||
}
|
||||
|
||||
static function joinWithSubscribers() {
|
||||
return static::joinWithTasks()
|
||||
->join(
|
||||
MP_SCHEDULED_TASK_SUBSCRIBERS_TABLE,
|
||||
'tasks.id = subscribers.task_id',
|
||||
'subscribers'
|
||||
);
|
||||
}
|
||||
|
||||
static function findTaskByNewsletterId($newsletter_id) {
|
||||
return static::joinWithTasks()
|
||||
->where('queues.newsletter_id', $newsletter_id);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user