PMCORE-2178 Migrate to queue job - Cron File: cron.php - Activity: emails
This commit is contained in:
committed by
Julio Cesar Laura Avendaño
parent
05c99db5c1
commit
ca82c81399
14
app/Jobs/TaskScheduler.php
Normal file
14
app/Jobs/TaskScheduler.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
class TaskScheduler extends QueuedClosure
|
||||
{
|
||||
/**
|
||||
* The number of times the job may be attempted.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $tries = 1;
|
||||
|
||||
}
|
||||
@@ -62,6 +62,14 @@ return [
|
||||
'days' => $app->make('config')->get('app.log_max_files', 60),
|
||||
],
|
||||
|
||||
'taskScheduler' => [
|
||||
'driver' => 'daily',
|
||||
'tap' => [App\Logging\CustomizeFormatter::class],
|
||||
'path' => storage_path('logs/taskScheduler.log'),
|
||||
'level' => 'debug',
|
||||
'days' => $app->make('config')->get('app.log_max_files', 60),
|
||||
],
|
||||
|
||||
'slack' => [
|
||||
'driver' => 'slack',
|
||||
'url' => env('LOG_SLACK_WEBHOOK_URL'),
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\unit\workflow\engine\src\ProcessMaker\TaskScheduler;
|
||||
|
||||
use App\Jobs\TaskScheduler;
|
||||
use Faker\Factory;
|
||||
use Illuminate\Support\Facades\Queue;
|
||||
use ProcessMaker\TaskScheduler\Task;
|
||||
use Tests\TestCase;
|
||||
|
||||
class TaskTest extends TestCase
|
||||
{
|
||||
private $faker;
|
||||
|
||||
/**
|
||||
* Method setUp.
|
||||
*/
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
$this->faker = Factory::create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method tearDown.
|
||||
*/
|
||||
protected function tearDown()
|
||||
{
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test synchronous asynchronous cases.
|
||||
*/
|
||||
public function asynchronousCases()
|
||||
{
|
||||
return [
|
||||
[true],
|
||||
[false]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* This test verify the setExecutionMessage method.
|
||||
* @test
|
||||
* @covers ProcessMaker\TaskScheduler\Task::runTask()
|
||||
* @covers ProcessMaker\TaskScheduler\Task::setExecutionMessage()
|
||||
* @dataProvider asynchronousCases
|
||||
*/
|
||||
public function it_should_test_setExecutionMessage_method($asynchronous)
|
||||
{
|
||||
$task = new Task($asynchronous, '');
|
||||
$message = $this->faker->paragraph;
|
||||
|
||||
ob_start();
|
||||
$task->setExecutionMessage($message);
|
||||
$printing = ob_get_clean();
|
||||
|
||||
//assert if message is contained in output buffer
|
||||
$this->assertRegExp("/{$message}/", $printing);
|
||||
}
|
||||
|
||||
/**
|
||||
* This test verify the setExecutionResultMessage method.
|
||||
* @test
|
||||
* @covers ProcessMaker\TaskScheduler\Task::runTask()
|
||||
* @covers ProcessMaker\TaskScheduler\Task::setExecutionResultMessage()
|
||||
* @dataProvider asynchronousCases
|
||||
*/
|
||||
public function it_should_test_setExecutionResultMessage_method($asynchronous)
|
||||
{
|
||||
$task = new Task($asynchronous, '');
|
||||
$message = $this->faker->paragraph;
|
||||
|
||||
ob_start();
|
||||
$task->setExecutionResultMessage($message, 'error');
|
||||
$printing = ob_get_clean();
|
||||
//assert if message is contained in output buffer
|
||||
$this->assertRegExp("/{$message}/", $printing);
|
||||
|
||||
ob_start();
|
||||
$task->setExecutionResultMessage($message, 'info');
|
||||
$printing = ob_get_clean();
|
||||
//assert if message is contained in output buffer
|
||||
$this->assertRegExp("/{$message}/", $printing);
|
||||
|
||||
ob_start();
|
||||
$task->setExecutionResultMessage($message, 'warning');
|
||||
$printing = ob_get_clean();
|
||||
//assert if message is contained in output buffer
|
||||
$this->assertRegExp("/{$message}/", $printing);
|
||||
}
|
||||
|
||||
/**
|
||||
* This test verify the saveLog method.
|
||||
* @test
|
||||
* @covers ProcessMaker\TaskScheduler\Task::runTask()
|
||||
* @covers ProcessMaker\TaskScheduler\Task::saveLog()
|
||||
* @dataProvider asynchronousCases
|
||||
*/
|
||||
public function it_should_test_saveLog_method($asynchronous)
|
||||
{
|
||||
$task = new Task($asynchronous, '');
|
||||
$description = $this->faker->paragraph;
|
||||
|
||||
$task->saveLog('', '', $description);
|
||||
$file = PATH_DATA . "log/cron.log";
|
||||
$this->assertFileExists($file);
|
||||
$contentLog = file_get_contents($file);
|
||||
$this->assertRegExp("/{$description}/", $contentLog);
|
||||
}
|
||||
|
||||
/**
|
||||
* This test verify the resendEmails activity method for synchronous and asynchronous execution.
|
||||
* @test
|
||||
* @covers ProcessMaker\TaskScheduler\Task::runTask()
|
||||
* @covers ProcessMaker\TaskScheduler\Task::resendEmails()
|
||||
* @dataProvider asynchronousCases
|
||||
*/
|
||||
public function it_should_test_resendEmails_method($asynchronous)
|
||||
{
|
||||
$task = new Task($asynchronous, '');
|
||||
$dateSystem = $this->faker->date();
|
||||
|
||||
//assert synchronous for cron file
|
||||
if ($asynchronous === false) {
|
||||
ob_start();
|
||||
$task->resendEmails('', $dateSystem);
|
||||
$printing = ob_get_clean();
|
||||
$this->assertRegExp("/DONE/", $printing);
|
||||
}
|
||||
|
||||
//assert asynchronous for job process
|
||||
if ($asynchronous === true) {
|
||||
Queue::fake();
|
||||
Queue::assertNothingPushed();
|
||||
$task->resendEmails('', $dateSystem);
|
||||
Queue::assertPushed(TaskScheduler::class);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,7 +128,8 @@ try {
|
||||
|
||||
if (in_array($arrayCommandOption['force'], $argv)) {
|
||||
unset($argv[array_search($arrayCommandOption['force'], $argv)]);
|
||||
|
||||
//reindex keys
|
||||
$argv = array_values($argv);
|
||||
$force = true;
|
||||
}
|
||||
|
||||
@@ -208,8 +209,8 @@ try {
|
||||
if (is_dir(PATH_DB . $entry)) {
|
||||
if (file_exists(PATH_DB . $entry . PATH_SEP . 'db.php')) {
|
||||
$counterw++;
|
||||
|
||||
passthru('php -f "' . $cronSinglePath . '" "' . base64_encode(PATH_HOME) . '" "' . base64_encode(PATH_TRUNK) . '" "' . base64_encode(PATH_OUTTRUNK) . '" ' . $cronName . ' ' . $entry . ' "' . $date . '" ' . $argvx);
|
||||
$command = 'php -f "' . $cronSinglePath . '" "' . base64_encode(PATH_HOME) . '" "' . base64_encode(PATH_TRUNK) . '" "' . base64_encode(PATH_OUTTRUNK) . '" ' . $cronName . ' ' . $entry . ' "' . $date . '" ' . $argvx;
|
||||
passthru($command);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -220,8 +221,8 @@ try {
|
||||
}
|
||||
|
||||
$counterw++;
|
||||
|
||||
passthru('php -f "' . $cronSinglePath . '" "' . base64_encode(PATH_HOME) . '" "' . base64_encode(PATH_TRUNK) . '" "' . base64_encode(PATH_OUTTRUNK) . '" ' . $cronName . ' ' . $workspace . ' "' . $date . '" ' . $argvx);
|
||||
$command = 'php -f "' . $cronSinglePath . '" "' . base64_encode(PATH_HOME) . '" "' . base64_encode(PATH_TRUNK) . '" "' . base64_encode(PATH_OUTTRUNK) . '" ' . $cronName . ' ' . $workspace . ' "' . $date . '" ' . $argvx;
|
||||
passthru($command);
|
||||
}
|
||||
|
||||
eprintln('Finished ' . $counterw . ' workspaces processed');
|
||||
@@ -241,6 +242,6 @@ try {
|
||||
} catch (Exception $e) {
|
||||
$token = strtotime("now");
|
||||
PMException::registerErrorLog($e, $token);
|
||||
G::outRes( G::LoadTranslation("ID_EXCEPTION_LOG_INTERFAZ", array($token)) . "\n" );
|
||||
G::outRes(G::LoadTranslation("ID_EXCEPTION_LOG_INTERFAZ", [$token]) . "\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ require_once __DIR__ . '/../../../bootstrap/app.php';
|
||||
use ProcessMaker\Core\JobsManager;
|
||||
use ProcessMaker\Core\System;
|
||||
use ProcessMaker\Plugins\PluginRegistry;
|
||||
use ProcessMaker\TaskScheduler\Task;
|
||||
|
||||
register_shutdown_function(function () {
|
||||
if (class_exists("Propel")) {
|
||||
@@ -55,6 +56,14 @@ try {
|
||||
$cronName = $argv[4];
|
||||
$workspace = $argv[5];
|
||||
$now = $argv[6]; //date
|
||||
//asynchronous flag
|
||||
$asynchronous = false;
|
||||
$result = array_search('+async', $argv);
|
||||
if ($result !== false && is_int($result)) {
|
||||
$asynchronous = true;
|
||||
unset($argv[$result]);
|
||||
$argv = array_values($argv);
|
||||
}
|
||||
//Defines constants
|
||||
define('PATH_SEP', ($osIsLinux) ? '/' : '\\');
|
||||
|
||||
@@ -280,7 +289,31 @@ try {
|
||||
try {
|
||||
switch ($cronName) {
|
||||
case 'cron':
|
||||
processWorkspace();
|
||||
try {
|
||||
$task = new Task($asynchronous, $sObject);
|
||||
if (empty($argvx) || strpos($argvx, "emails") !== false) {
|
||||
$task->resendEmails($now, $dateSystem);
|
||||
}
|
||||
unpauseApplications();
|
||||
calculateDuration();
|
||||
/*----------------------------------********---------------------------------*/
|
||||
calculateAppDuration();
|
||||
/*----------------------------------********---------------------------------*/
|
||||
executeEvents();
|
||||
executeScheduledCases();
|
||||
executeUpdateAppTitle();
|
||||
executeCaseSelfService();
|
||||
cleanSelfServiceTables();
|
||||
executePlugins();
|
||||
/*----------------------------------********---------------------------------*/
|
||||
fillReportByUser();
|
||||
fillReportByProcess();
|
||||
synchronizeDrive();
|
||||
synchronizeGmailLabels();
|
||||
/*----------------------------------********---------------------------------*/
|
||||
} catch (Exception $oError) {
|
||||
saveLog("main", "error", "Error processing workspace : " . $oError->getMessage() . "\n");
|
||||
}
|
||||
break;
|
||||
case 'ldapcron':
|
||||
require_once(PATH_HOME . 'engine' . PATH_SEP . 'methods' . PATH_SEP . 'services' . PATH_SEP . 'ldapadvanced.php');
|
||||
@@ -328,101 +361,6 @@ try {
|
||||
G::outRes(G::LoadTranslation("ID_EXCEPTION_LOG_INTERFAZ", array($token)) . "\n");
|
||||
}
|
||||
|
||||
//Functions
|
||||
function processWorkspace()
|
||||
{
|
||||
try {
|
||||
global $sObject;
|
||||
global $sLastExecution;
|
||||
|
||||
resendEmails();
|
||||
unpauseApplications();
|
||||
calculateDuration();
|
||||
/*----------------------------------********---------------------------------*/
|
||||
calculateAppDuration();
|
||||
/*----------------------------------********---------------------------------*/
|
||||
executeEvents($sLastExecution);
|
||||
executeScheduledCases();
|
||||
executeUpdateAppTitle();
|
||||
executeCaseSelfService();
|
||||
cleanSelfServiceTables();
|
||||
executePlugins();
|
||||
/*----------------------------------********---------------------------------*/
|
||||
fillReportByUser();
|
||||
fillReportByProcess();
|
||||
synchronizeDrive();
|
||||
synchronizeGmailLabels();
|
||||
/*----------------------------------********---------------------------------*/
|
||||
} catch (Exception $oError) {
|
||||
saveLog("main", "error", "Error processing workspace : " . $oError->getMessage() . "\n");
|
||||
}
|
||||
}
|
||||
|
||||
function resendEmails()
|
||||
{
|
||||
global $argvx;
|
||||
global $now;
|
||||
global $dateSystem;
|
||||
|
||||
if ($argvx != "" && strpos($argvx, "emails") === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
setExecutionMessage("Resending emails");
|
||||
|
||||
try {
|
||||
$dateResend = $now;
|
||||
|
||||
if ($now == $dateSystem) {
|
||||
$arrayDateSystem = getdate(strtotime($dateSystem));
|
||||
|
||||
$mktDateSystem = mktime(
|
||||
$arrayDateSystem["hours"],
|
||||
$arrayDateSystem["minutes"],
|
||||
$arrayDateSystem["seconds"],
|
||||
$arrayDateSystem["mon"],
|
||||
$arrayDateSystem["mday"],
|
||||
$arrayDateSystem["year"]
|
||||
);
|
||||
|
||||
$dateResend = date("Y-m-d H:i:s", $mktDateSystem - (7 * 24 * 60 * 60));
|
||||
}
|
||||
|
||||
$oSpool = new SpoolRun();
|
||||
$oSpool->resendEmails($dateResend, 1);
|
||||
|
||||
saveLog("resendEmails", "action", "Resending Emails", "c");
|
||||
|
||||
$aSpoolWarnings = $oSpool->getWarnings();
|
||||
|
||||
if ($aSpoolWarnings !== false) {
|
||||
foreach ($aSpoolWarnings as $sWarning) {
|
||||
print("MAIL SPOOL WARNING: " . $sWarning . "\n");
|
||||
saveLog("resendEmails", "warning", "MAIL SPOOL WARNING: " . $sWarning);
|
||||
}
|
||||
}
|
||||
|
||||
setExecutionResultMessage("DONE");
|
||||
} catch (Exception $e) {
|
||||
$c = new Criteria("workflow");
|
||||
$c->clearSelectColumns();
|
||||
$c->addSelectColumn(ConfigurationPeer::CFG_UID);
|
||||
$c->add(ConfigurationPeer::CFG_UID, "Emails");
|
||||
$result = ConfigurationPeer::doSelectRS($c);
|
||||
$result->setFetchmode(ResultSet::FETCHMODE_ASSOC);
|
||||
if ($result->next()) {
|
||||
setExecutionResultMessage("WARNING", "warning");
|
||||
$message = "Emails won't be sent, but the cron will continue its execution";
|
||||
eprintln(" '-" . $message, "yellow");
|
||||
} else {
|
||||
setExecutionResultMessage("WITH ERRORS", "error");
|
||||
eprintln(" '-" . $e->getMessage(), "red");
|
||||
}
|
||||
|
||||
saveLog("resendEmails", "error", "Error Resending Emails: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
function unpauseApplications()
|
||||
{
|
||||
global $argvx;
|
||||
@@ -570,8 +508,9 @@ function calculateAppDuration()
|
||||
}
|
||||
/*----------------------------------********---------------------------------*/
|
||||
|
||||
function executeEvents($sLastExecution, $now = null)
|
||||
function executeEvents()
|
||||
{
|
||||
global $sLastExecution;
|
||||
global $argvx;
|
||||
global $now;
|
||||
|
||||
@@ -859,6 +798,14 @@ function executeCaseSelfService()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This function is only used in this file and must be deleted.
|
||||
* @global string $sObject
|
||||
* @global string $isDebug
|
||||
* @param string $sSource
|
||||
* @param string $sType
|
||||
* @param string $sDescription
|
||||
*/
|
||||
function saveLog($sSource, $sType, $sDescription)
|
||||
{
|
||||
try {
|
||||
@@ -876,6 +823,10 @@ function saveLog($sSource, $sType, $sDescription)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This function is only used in this file and must be deleted.
|
||||
* @param string $m
|
||||
*/
|
||||
function setExecutionMessage($m)
|
||||
{
|
||||
$len = strlen($m);
|
||||
@@ -889,6 +840,11 @@ function setExecutionMessage($m)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This function is only used in this file and must be deleted.
|
||||
* @param string $m
|
||||
* @param string $t
|
||||
*/
|
||||
function setExecutionResultMessage($m, $t = '')
|
||||
{
|
||||
$c = 'green';
|
||||
|
||||
185
workflow/engine/src/ProcessMaker/TaskScheduler/Task.php
Normal file
185
workflow/engine/src/ProcessMaker/TaskScheduler/Task.php
Normal file
@@ -0,0 +1,185 @@
|
||||
<?php
|
||||
|
||||
namespace ProcessMaker\TaskScheduler;
|
||||
|
||||
use App\Jobs\TaskScheduler;
|
||||
use Bootstrap;
|
||||
use ConfigurationPeer;
|
||||
use Criteria;
|
||||
use Exception;
|
||||
use G;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use ProcessMaker\Core\JobsManager;
|
||||
use ResultSet;
|
||||
use SpoolRun;
|
||||
|
||||
class Task
|
||||
{
|
||||
/**
|
||||
* Property asynchronous,
|
||||
* @var bool
|
||||
*/
|
||||
private $asynchronous;
|
||||
|
||||
/**
|
||||
* Property object
|
||||
* @var mix
|
||||
*/
|
||||
private $object;
|
||||
|
||||
/**
|
||||
* Constructor class.
|
||||
* @param bool $async
|
||||
* @param mix $object
|
||||
*/
|
||||
public function __construct(bool $asynchronous, $object)
|
||||
{
|
||||
$this->asynchronous = $asynchronous;
|
||||
$this->object = $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run job, the property async indicate if is synchronous or asynchronous.
|
||||
* @param callable $job
|
||||
*/
|
||||
private function runTask(callable $job)
|
||||
{
|
||||
if ($this->asynchronous === false) {
|
||||
$job();
|
||||
}
|
||||
if ($this->asynchronous === true) {
|
||||
JobsManager::getSingleton()->dispatch(TaskScheduler::class, $job);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print start message in console.
|
||||
* @param string $message
|
||||
*/
|
||||
public function setExecutionMessage(string $message)
|
||||
{
|
||||
Log::channel('taskScheduler:taskScheduler')->info($message, Bootstrap::context());
|
||||
$len = strlen($message);
|
||||
$linesize = 60;
|
||||
$rOffset = $linesize - $len;
|
||||
|
||||
eprint("* $message");
|
||||
|
||||
for ($i = 0; $i < $rOffset; $i++) {
|
||||
eprint('.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print result message in console.
|
||||
* @param string $message
|
||||
* @param string $type
|
||||
*/
|
||||
public function setExecutionResultMessage(string $message, string $type = '')
|
||||
{
|
||||
$color = 'green';
|
||||
if ($type == 'error') {
|
||||
$color = 'red';
|
||||
Log::channel('taskScheduler:taskScheduler')->error($message, Bootstrap::context());
|
||||
}
|
||||
if ($type == 'info') {
|
||||
$color = 'yellow';
|
||||
Log::channel('taskScheduler:taskScheduler')->info($message, Bootstrap::context());
|
||||
}
|
||||
if ($type == 'warning') {
|
||||
$color = 'yellow';
|
||||
Log::channel('taskScheduler:taskScheduler')->warning($message, Bootstrap::context());
|
||||
}
|
||||
eprintln("[$message]", $color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save logs.
|
||||
* @param string $source
|
||||
* @param string $type
|
||||
* @param string $description
|
||||
*/
|
||||
public function saveLog(string $source, string $type, string $description)
|
||||
{
|
||||
$context = [
|
||||
'type' => $type,
|
||||
'description' => $description
|
||||
];
|
||||
Log::channel('taskScheduler:taskScheduler')->info($source, Bootstrap::context($context));
|
||||
try {
|
||||
G::verifyPath(PATH_DATA . "log" . PATH_SEP, true);
|
||||
G::log("| $this->object | " . $source . " | $type | " . $description, PATH_DATA);
|
||||
} catch (Exception $e) {
|
||||
Log::channel('taskScheduler:taskScheduler')->error($e->getMessage(), Bootstrap::context($context));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This resend the emails.
|
||||
* @param string $now
|
||||
* @param string $dateSystem
|
||||
*/
|
||||
public function resendEmails($now, $dateSystem)
|
||||
{
|
||||
$job = function() use($now, $dateSystem) {
|
||||
$this->setExecutionMessage("Resending emails");
|
||||
|
||||
try {
|
||||
$dateResend = $now;
|
||||
|
||||
if ($now == $dateSystem) {
|
||||
$arrayDateSystem = getdate(strtotime($dateSystem));
|
||||
|
||||
$mktDateSystem = mktime(
|
||||
$arrayDateSystem["hours"],
|
||||
$arrayDateSystem["minutes"],
|
||||
$arrayDateSystem["seconds"],
|
||||
$arrayDateSystem["mon"],
|
||||
$arrayDateSystem["mday"],
|
||||
$arrayDateSystem["year"]
|
||||
);
|
||||
|
||||
$dateResend = date("Y-m-d H:i:s", $mktDateSystem - (7 * 24 * 60 * 60));
|
||||
}
|
||||
|
||||
$spoolRun = new SpoolRun();
|
||||
$spoolRun->resendEmails($dateResend, 1);
|
||||
|
||||
$this->saveLog("resendEmails", "action", "Resending Emails", "c");
|
||||
|
||||
$spoolWarnings = $spoolRun->getWarnings();
|
||||
|
||||
if ($spoolWarnings !== false) {
|
||||
foreach ($spoolWarnings as $warning) {
|
||||
print("MAIL SPOOL WARNING: " . $warning . "\n");
|
||||
$this->saveLog("resendEmails", "warning", "MAIL SPOOL WARNING: " . $warning);
|
||||
}
|
||||
}
|
||||
|
||||
$this->setExecutionResultMessage("DONE");
|
||||
} catch (Exception $e) {
|
||||
$context = [
|
||||
"trace" => $e->getTraceAsString()
|
||||
];
|
||||
Log::channel('taskScheduler:taskScheduler')->error($e->getMessage(), Bootstrap::context($context));
|
||||
$criteria = new Criteria("workflow");
|
||||
$criteria->clearSelectColumns();
|
||||
$criteria->addSelectColumn(ConfigurationPeer::CFG_UID);
|
||||
$criteria->add(ConfigurationPeer::CFG_UID, "Emails");
|
||||
$result = ConfigurationPeer::doSelectRS($criteria);
|
||||
$result->setFetchmode(ResultSet::FETCHMODE_ASSOC);
|
||||
if ($result->next()) {
|
||||
$this->setExecutionResultMessage("WARNING", "warning");
|
||||
$message = "Emails won't be sent, but the cron will continue its execution";
|
||||
eprintln(" '-" . $message, "yellow");
|
||||
} else {
|
||||
$this->setExecutionResultMessage("WITH ERRORS", "error");
|
||||
eprintln(" '-" . $e->getMessage(), "red");
|
||||
}
|
||||
|
||||
$this->saveLog("resendEmails", "error", "Error Resending Emails: " . $e->getMessage());
|
||||
}
|
||||
};
|
||||
$this->runTask($job);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user