Compare commits

...

4 Commits

Author SHA1 Message Date
0fe57f61e6 Release 3.100.1 2022-10-06 13:07:26 +03:00
1ed669da01 Delete task when no newsletter was found
When no corresponding newsletter was found the task can be deleted. The behavior
before meant that such a task would remain forever in the database with the
status 'running'.

[MAILPOET-4699]
2022-10-06 12:30:05 +03:00
86ddf98b7c Allow newsletter_id to be NULL in sending_queue table
[MAILPOET-4699]
2022-10-06 12:19:31 +03:00
cb575f1972 Improve logging of errors in cron
Sometimes errors overlap each other so that the 'Last Seen error' we log
does not provide sufficient information on the cause of a problem.

E.g. one worker might cause an SQL issue, which closes the EntityManager and a
subsequent worker might overwrite this error with the information that the
EntityManager is closed.

With this commit, both those issues will be logged as an error.

[MAILPOET-4699]
2022-10-06 12:19:25 +03:00
9 changed files with 53 additions and 18 deletions

View File

@ -218,7 +218,7 @@ class Migrator {
$attributes = [
'id int(11) unsigned NOT NULL AUTO_INCREMENT,',
'task_id int(11) unsigned NOT NULL,',
'newsletter_id int(11) unsigned NOT NULL,',
'newsletter_id int(11) unsigned NULL,',
'newsletter_rendered_body longtext,',
'newsletter_rendered_subject varchar(250) NULL DEFAULT NULL,',
'subscribers longtext,',

View File

@ -3,6 +3,7 @@
namespace MailPoet\Cron;
use MailPoet\Entities\ScheduledTaskEntity;
use MailPoet\Logging\LoggerFactory;
use MailPoet\Newsletter\Sending\ScheduledTasksRepository;
use MailPoet\WP\Functions as WPFunctions;
use MailPoetVendor\Carbon\Carbon;
@ -27,17 +28,22 @@ class CronWorkerRunner {
/** @var ScheduledTasksRepository */
private $scheduledTasksRepository;
/** @var LoggerFactory */
private $loggerFactory;
public function __construct(
CronHelper $cronHelper,
CronWorkerScheduler $cronWorkerScheduler,
WPFunctions $wp,
ScheduledTasksRepository $scheduledTasksRepository
ScheduledTasksRepository $scheduledTasksRepository,
LoggerFactory $loggerFactory
) {
$this->timer = microtime(true);
$this->cronHelper = $cronHelper;
$this->cronWorkerScheduler = $cronWorkerScheduler;
$this->wp = $wp;
$this->scheduledTasksRepository = $scheduledTasksRepository;
$this->loggerFactory = $loggerFactory;
}
public function run(CronWorkerInterface $worker) {
@ -72,6 +78,10 @@ class CronWorkerRunner {
}
} catch (\Exception $e) {
if (isset($task) && $task && $e->getCode() !== CronHelper::DAEMON_EXECUTION_LIMIT_REACHED) {
/**
* ToDo: Use \LoggerFactory::TOPIC_CRON as logger topic, once it is available
*/
$this->loggerFactory->getLogger()->error($e->getMessage(), ['error' => $e]);
$this->cronWorkerScheduler->rescheduleProgressively($task);
}
throw $e;

View File

@ -3,6 +3,7 @@
namespace MailPoet\Cron;
use MailPoet\Cron\Workers\WorkersFactory;
use MailPoet\Logging\LoggerFactory;
class Daemon {
public $timer;
@ -16,15 +17,20 @@ class Daemon {
/** @var WorkersFactory */
private $workersFactory;
/** @var LoggerFactory */
private $loggerFactory;
public function __construct(
CronHelper $cronHelper,
CronWorkerRunner $cronWorkerRunner,
WorkersFactory $workersFactory
WorkersFactory $workersFactory,
LoggerFactory $loggerFactory
) {
$this->timer = microtime(true);
$this->workersFactory = $workersFactory;
$this->cronWorkerRunner = $cronWorkerRunner;
$this->cronHelper = $cronHelper;
$this->loggerFactory = $loggerFactory;
}
public function run($settingsDaemonData) {
@ -41,10 +47,16 @@ class Daemon {
}
} catch (\Exception $e) {
$workerClassNameParts = explode('\\', get_class($worker));
$workerName = end($workerClassNameParts);
$errors[] = [
'worker' => end($workerClassNameParts),
'worker' => $workerName,
'message' => $e->getMessage(),
];
/**
* ToDo: Use \LoggerFactory::TOPIC_CRON as logger topic, once it is available
*/
$this->loggerFactory->getLogger()->error($e->getMessage(), ['error' => $e, 'worker' => $workerName]);
}
}

View File

@ -156,22 +156,20 @@ class SendingQueue {
$newsletterEntity = $this->newsletterTask->getNewsletterFromQueue($queue);
if (!$newsletterEntity) {
$this->deleteTask($queue);
return;
}
$newsletter = Newsletter::findOne($newsletterEntity->getId());
if (!$newsletter) {
$this->deleteTask($queue);
return;
}
// pre-process newsletter (render, replace shortcodes/links, etc.)
$newsletter = $this->newsletterTask->preProcessNewsletter($newsletter, $queue);
if (!$newsletter) {
$this->loggerFactory->getLogger(LoggerFactory::TOPIC_NEWSLETTERS)->info(
'delete task in sending queue',
['task_id' => $queue->taskId]
);
$queue->delete();
$this->deleteTask($queue);
return;
}
// clone the original object to be used for processing
@ -264,6 +262,14 @@ class SendingQueue {
}
}
private function deleteTask(SendingTask $queue) {
$this->loggerFactory->getLogger(LoggerFactory::TOPIC_NEWSLETTERS)->info(
'delete task in sending queue',
['task_id' => $queue->taskId]
);
$queue->delete();
}
public function getBatchSize(): int {
return $this->throttlingHandler->getBatchSize();
}

View File

@ -2,7 +2,7 @@
/*
* Plugin Name: MailPoet
* Version: 3.100.0
* Version: 3.100.1
* Plugin URI: http://www.mailpoet.com
* Description: Create and send newsletters, post notifications and welcome emails from your WordPress.
* Author: MailPoet
@ -17,7 +17,7 @@
*/
$mailpoetPlugin = [
'version' => '3.100.0',
'version' => '3.100.1',
'filename' => __FILE__,
'path' => dirname(__FILE__),
'autoloader' => dirname(__FILE__) . '/vendor/autoload.php',

View File

@ -3,7 +3,7 @@ Contributors: mailpoet
Tags: email, email marketing, post notification, woocommerce emails, email automation, newsletter, newsletter builder, newsletter subscribers
Requires at least: 5.6
Tested up to: 6.0
Stable tag: 3.100.0
Stable tag: 3.100.1
Requires PHP: 7.2
License: GPLv3
License URI: https://www.gnu.org/licenses/gpl-3.0.html
@ -219,6 +219,9 @@ Check our [Knowledge Base](https://kb.mailpoet.com) or contact us through our [s
== Changelog ==
= 3.100.1 - 2022-10-06 =
* Fixed: In some instances the sending stuck because the EntityManager was closed.
= 3.100.0 - 2022-10-03 =
* Added: tagging subscribers when signed up via a form;
* Improved: linux cron error message;

View File

@ -9,6 +9,7 @@ use MailPoet\Cron\CronWorkerRunner;
use MailPoet\Cron\CronWorkerScheduler;
use MailPoet\Cron\Workers\SimpleWorkerMockImplementation;
use MailPoet\Entities\ScheduledTaskEntity;
use MailPoet\Logging\LoggerFactory;
use MailPoet\Newsletter\Sending\ScheduledTasksRepository;
use MailPoet\Test\DataFactories\ScheduledTask as ScheduledTaskFactory;
use MailPoet\WP\Functions as WPFunctions;
@ -33,7 +34,8 @@ class CronWorkerRunnerTest extends \MailPoetTest {
$this->cronHelper,
$this->diContainer->get(CronWorkerScheduler::class),
$this->diContainer->get(WPFunctions::class),
$this->scheduledTasksRepository
$this->scheduledTasksRepository,
$this->diContainer->get(LoggerFactory::class)
);
}

View File

@ -11,6 +11,7 @@ use MailPoet\Cron\DaemonHttpRunner;
use MailPoet\Cron\Triggers\WordPress;
use MailPoet\Cron\Workers\SimpleWorker;
use MailPoet\Cron\Workers\WorkersFactory;
use MailPoet\Logging\LoggerFactory;
use MailPoet\Settings\SettingsController;
use MailPoet\Settings\SettingsRepository;
use MailPoet\WP\Functions as WPFunctions;
@ -79,7 +80,7 @@ class DaemonHttpRunnerTest extends \MailPoetTest {
->method('run')
->willThrowException(new \Exception());
$daemon = new Daemon($this->cronHelper, $cronWorkerRunnerMock, $this->createWorkersFactoryMock());
$daemon = new Daemon($this->cronHelper, $cronWorkerRunnerMock, $this->createWorkersFactoryMock(), $this->diContainer->get(LoggerFactory::class));
$daemonHttpRunner = $this->make(DaemonHttpRunner::class, [
'pauseExecution' => null,
'callSelf' => null,
@ -205,7 +206,7 @@ class DaemonHttpRunnerTest extends \MailPoetTest {
$cronWorkerRunner = $this->make(CronWorkerRunner::class, [
'run' => null,
]);
$daemon = new Daemon($this->cronHelper, $cronWorkerRunner, $this->createWorkersFactoryMock());
$daemon = new Daemon($this->cronHelper, $cronWorkerRunner, $this->createWorkersFactoryMock(), $this->diContainer->get(LoggerFactory::class));
$daemonHttpRunner->__construct($daemon, $this->cronHelper, SettingsController::getInstance(), $this->diContainer->get(WordPress::class));
$daemonHttpRunner->run($data);
$updatedDaemon = $this->settings->get(CronHelper::DAEMON_SETTING);
@ -225,7 +226,7 @@ class DaemonHttpRunnerTest extends \MailPoetTest {
->method('run')
->willThrowException(new \Exception());
$daemon = new Daemon($this->cronHelper, $cronWorkerRunnerMock, $this->createWorkersFactoryMock());
$daemon = new Daemon($this->cronHelper, $cronWorkerRunnerMock, $this->createWorkersFactoryMock(), $this->diContainer->get(LoggerFactory::class));
$daemonHttpRunner = $this->make(DaemonHttpRunner::class, [
'pauseExecution' => null,
'callSelf' => null,
@ -261,7 +262,7 @@ class DaemonHttpRunnerTest extends \MailPoetTest {
$cronWorkerRunnerMock = $this->make(CronWorkerRunner::class, [
'run' => null,
]);
$daemon = new Daemon($this->cronHelper, $cronWorkerRunnerMock, $this->createWorkersFactoryMock());
$daemon = new Daemon($this->cronHelper, $cronWorkerRunnerMock, $this->createWorkersFactoryMock(), $this->diContainer->get(LoggerFactory::class));
$daemonHttpRunner->__construct($daemon, $this->cronHelper, SettingsController::getInstance(), $this->diContainer->get(WordPress::class));
$daemonHttpRunner->run($data);
expect(ignore_user_abort())->equals(true);

View File

@ -8,6 +8,7 @@ use MailPoet\Cron\CronWorkerRunner;
use MailPoet\Cron\Daemon;
use MailPoet\Cron\Workers\SimpleWorker;
use MailPoet\Cron\Workers\WorkersFactory;
use MailPoet\Logging\LoggerFactory;
use MailPoet\Settings\SettingsController;
use MailPoet\Settings\SettingsRepository;
@ -31,7 +32,7 @@ class DaemonTest extends \MailPoetTest {
'token' => 123,
];
$this->settings->set(CronHelper::DAEMON_SETTING, $data);
$daemon = new Daemon($this->cronHelper, $cronWorkerRunner, $this->createWorkersFactoryMock());
$daemon = new Daemon($this->cronHelper, $cronWorkerRunner, $this->createWorkersFactoryMock(), $this->diContainer->get(LoggerFactory::class));
$daemon->run($data);
}